zoukankan      html  css  js  c++  java
  • 2019.10.30 csp-s模拟测试94 反思总结

    头一次做图巨的模拟题OWO

    自从上一次听图巨讲课然后骗了小礼物以后一直对图巨印象挺好的233

    T1:

    对于XY取对数=Y*log(x)

    对于Y!取对数=log(1*2*3*...*Y)=log1+log2+log3+...+logY

    因为数字大小不超过1e5,直接累加最后比较就可以了

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    int t,x,y;
    double a,b;
    int main()
    {
        freopen("yuuutsu.in","r",stdin);
        freopen("yuuutsu.out","w",stdout);
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&x,&y);
            a=y*log(x);
            b=0;
            for(int i=1;i<=y;i++){
                b+=log(i);
            }
            if(a<=b)printf("Yes
    ");
            else printf("No
    ");
        }
        return 0;
    }
    View Code

    T2:

    每一次操作会让区间整体加或减->在差分数组上首位加减

    列出目标序列的差分数组,可以进行操作让一个位置的数字移动k步,如果有大小相同的数字撞在一起就会消掉,不同的话可以合并。想起星空这道题,不同的是今天的T2只能走k一种步数且差分值并不只代表一种状态

    目标是要让所有的值变成0,又想到一道跳斑马线的题……?考虑把位置对于k取模余数不同的数字分开处理。维护位置对于k取模后余数为下标,记录差分值之和的m数组。用树状数组维护当前的m是否都为0。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=2e6+10;
    int n,k,q,a[N],sum[N],m[N];
    long long tree[N];
    void add(int x,int y){
        for(;x<=k;x+=(x&-x))tree[x]+=y;
    }
    long long ask(int x){
        long long num=0;
        for(;x;x-=(x&-x))num+=tree[x];
        return num;
    }
    int main()
    {
        freopen("august.in","r",stdin);
        freopen("august.out","w",stdout);
        scanf("%d%d%d",&n,&k,&q);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            m[i%k]+=a[i]-a[i-1];
        }
        m[(n+1)%k]+=-a[n];
        for(int i=0;i<k;i++){
            add(i+1,(m[i]!=0));
        }
        if(!ask(k))printf("Yes
    ");
        else printf("No
    ");
        for(int i=1,x,pos;i<=q;i++){
            scanf("%d%d",&pos,&x);
            int pos0=pos%k,pos1=(pos+1)%k;
            int val=(m[pos0]!=0),val1=(m[pos1]!=0);
            m[pos0]=m[pos0]-a[pos]+a[pos-1];
            m[pos1]=m[pos1]-a[pos+1]+a[pos];
            a[pos]+=x;
            m[pos0]=m[pos0]+a[pos]-a[pos-1];
            m[pos1]=m[pos1]+a[pos+1]-a[pos];
            add(pos0+1,(m[pos0]!=0)-val);
            add(pos1+1,(m[pos1]!=0)-val1);
            if(!ask(k))printf("Yes
    ");
            else printf("No
    ");
        }
        return 0;
    }
    View Code

     发现自己对于m是否都为0的处理过于麻烦了…这是何种山路十八弯的脑回路才会想到这种处理…

    其实是中途思路锅了,保留了树状数组的写法XD其实直接记一个m不为0的数量,每次m变化的时候进行更新就好了

    T3:

    将问题转化成,对于树上的一个点,会对多少区间产生贡献。

    线段树维护子树中存在哪些位置的点,线段树下标是在a数组中的位置。如果这个点可以对一段区间产生贡献,那么这段区间在线段树种一定是连续的1,中间若存在0则代表这段区间中在更高的地方存在点。在线段树上统计答案,记录线段树每个节点从左端点开始最长的一段1的长度lonl,从右端点开始最长的一段1的长度lonr,以及包含的区间个数val。val=左儿子的val+右儿子的val+左儿子lonr*右儿子lonl(端点在两边的区间数量)。这样计算一定不重不漏,有线段树分治的意味。

    维护节点x的线段树的时候,对所有儿子进行线段树合并,再把x点insert进去。注意当前节点线段树root的区间个数要减去节点儿子们的区间个数,才能用来累计答案。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=2000010;
    int n,tot,cnt;
    int ver[N],Next[N],head[N];
    int a[N],b[N],pos[N],T[N],L[N*22],R[N*22],lonl[N*22],lonr[N*22];
    long long ans,sum[N],val[N*22];
    void add(int x,int y){
        ver[++tot]=y;
        Next[tot]=head[x];
        head[x]=tot;
    }
    void update(int p,int l,int r){
        int mid=(l+r)/2;
        if(lonl[L[p]]==mid-l+1)lonl[p]=mid-l+1+lonl[R[p]];
        else lonl[p]=lonl[L[p]];
        if(lonr[R[p]]==r-mid)lonr[p]=r-mid+lonr[L[p]];
        else lonr[p]=lonr[R[p]];
        val[p]=val[L[p]]+val[R[p]]+1ll*lonr[L[p]]*lonl[R[p]];
    }
    void change(int &p,int p0,int l,int r){
        if(!p){
            p=p0;
            return;
        }
        int mid=(l+r)/2;
        if(L[p0])change(L[p],L[p0],l,mid);
        if(R[p0])change(R[p],R[p0],mid+1,r);
        update(p,l,r);
    }
    void ins(int &p,int l,int r,int pos){
        if(!p)p=++cnt;
        if(l==r){
            lonl[p]=lonr[p]=1;
            val[p]=0;
            return;
        }
        int mid=(l+r)/2;
        if(pos<=mid)ins(L[p],l,mid,pos);
        else ins(R[p],mid+1,r,pos);
        update(p,l,r);
    }
    void dfs(int x){
        for(int i=head[x];i;i=Next[i]){
            int y=ver[i];
            dfs(y);
            sum[x]+=sum[y];
            change(T[x],T[y],1,n);
        }
        ins(T[x],1,n,pos[x]);
        long long num=val[T[x]];
        ans+=(num-sum[x])*b[x];
        sum[x]=num;
    }
    int main()
    {
        freopen("sagittarius.in","r",stdin);
        freopen("sagittarius.out","w",stdout);
        scanf("%d",&n);
        for(int i=2,x;i<=n;i++){
            scanf("%d",&x);
            add(x,i);
    //        st[i][0]=x;
        }
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),pos[a[i]]=i;
        for(int i=1;i<=n;i++)scanf("%d",&b[i]),ans+=b[i];
        dfs(1);
        printf("%lld
    ",ans);
        return 0;
        
    }
    View Code
  • 相关阅读:
    Quartz.NET-2.3.3 各种 数据库配置 类别大全
    C#获取当前路径的七种方法 【转载】
    BCB 如何拦截TAB键消息
    用union 和 struct 位域操作
    表值函数
    C#中 委托和事件的关系
    关于C++ Builder Codegurad 问题的排查。
    存储过程中使用事务的“正规”写法
    C++ 中对vector<T*> 数组的查找和排序
    BCB 中 Application->CreateForm 和 New 的一个区别
  • 原文地址:https://www.cnblogs.com/chloris/p/11768151.html
Copyright © 2011-2022 走看看