• CF444(Div. 1简单题解)


    A .DZY Loves Physics

    题意:给定带点权和边权的无向图,现在让你选一些点,使得 点权和/被选点对间的边权和 最大。

    思路:不难证明,选择边和对应的两点是最优的。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=200010;
    double a[maxn],ans;
    int main()
    {
        int N,M,u,v; double x;
        scanf("%d%d",&N,&M);
        rep(i,1,N) scanf("%lf",&a[i]);
        rep(i,1,M){
            scanf("%d%d%lf",&u,&v,&x);
            ans=max(ans,(a[u]+a[v])/x);
        }
        printf("%.10lf
    ",ans);
        return 0;
    }

    B .DZY Loves FFT

    题意:给定a数组,范围是1到N;b数组,是0或者1 。a数组和b数组都是随机的。 然后给定规则,ci=max(aj*bk);满足i=j+k。现在让你求c数组。

    思路: 如果b的1的个数比较少,比如num=少于100,我们可以直接暴力,复杂度O(num*N); 如果1的个数比较多,那么我们可以大胆猜测,排名在前面的S个可以去更新很多地方的答案,假设S=40。 那么只剩下很少的没有被更新,对于这些,我们去暴力更新即可。 复杂度O(40*N+...)

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=200010;
    int N,D,a[maxn],b[maxn],c[maxn],tot;
    int pos[maxn],ans[maxn],X;
    int getNextX(){
        X=(37LL*X+10007)%1000000007;
        return X;
    }
    int initAB() {
        rep(i,0,N-1) a[i]=i+1;
        rep(i,0,N-1) swap(a[i],a[getNextX()%(i+1)]);
        rep(i,0,N-1){
            if(i<D) b[i]=1;
            else b[i]=0;
        }
        rep(i,0,N-1) swap(b[i],b[getNextX()%(i+1)]);
    }
    void get(int p)
    {
         rep(j,1,tot){
            if(c[j]>p) break;
            ans[p]=max(ans[p],a[p-c[j]]);
         }
    }
    int main()
    {
        scanf("%d%d%d",&N,&D,&X);
        initAB();
        rep(i,0,N-1) pos[a[i]]=i;
        rep(i,0,N-1) if(b[i]) c[++tot]=i;
        if(D<100){
            rep(i,0,N-1)
             rep(j,1,tot)
              ans[i+c[j]]=max(ans[i+c[j]],a[i]);
        }
        else {
            int B=min(N-1,40);
            rep(i,N-B,N){
               int p=pos[i];
               rep(j,1,tot) {
                 if(c[j]>N-p) break;
                 ans[p+c[j]]=max(ans[p+c[j]],a[p]);
               }
            }
            rep(i,0,N-1) if(!ans[i]) get(i);
        }
        rep(i,0,N-1) printf("%d
    ",ans[i]);
        return 0;
    }

    C .DZY Loves Colors

    题意:有一排物体,一开始颜色分别是1到N。假如一个物体颜色是col,修改为x,那么他增加的炫丽度=abs(col-x);现在进行Q次操作,1操作是区间修改颜色; 2操作是询问区间炫丽度之和。(N<1e5);

    思路:由于要查询区间炫丽度,所以还没法用老司机树,毕竟odt没有历史记录。 所以我们还是用线段树,依然是利用其相同线段的势能关系来解决这个问题。

    我们对于颜色相同的区间,可以对其进行lazy操作。  lazy维护一个颜色,和一个加的值。 这样的话,有些中间的变化量就可以不用去考虑了。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=400010;
    int col[maxn]; ll add[maxn],sum[maxn];
    void build(int Now,int L,int R)
    {
        if(L==R){ col[Now]=L;return;}
        int Mid=(L+R)>>1;
        build(Now<<1,L,Mid);
        build(Now<<1|1,Mid+1,R);
    }
    void pushdown(int Now,int L,int R)
    {
        if(col[Now]){
            col[Now<<1]=col[Now<<1|1]=col[Now];
        }
        if(add[Now]) {
            int Mid=(L+R)>>1;
            sum[Now<<1]+=1LL*(Mid-L+1)*add[Now];
            sum[Now<<1|1]+=1LL*(R-Mid)*add[Now];
            add[Now<<1]+=add[Now]; add[Now<<1|1]+=add[Now];
            add[Now]=0;
        }
    }
    void pushup(int Now)
    {
        sum[Now]=sum[Now<<1]+sum[Now<<1|1];
        if(col[Now<<1]==col[Now<<1|1]) col[Now]=col[Now<<1];
        else col[Now]=0;
    }
    void update(int Now,int L,int R,int l,int r,int x)
    {
        if(l<=L&&r>=R&&col[Now]){
            add[Now]+=abs(x-col[Now]);
            sum[Now]+=1LL*abs(x-col[Now])*(R-L+1);
            col[Now]=x; return ;
        }
        pushdown(Now,L,R); int Mid=(L+R)>>1;
        if(l<=Mid) update(Now<<1,L,Mid,l,r,x);
        if(r>Mid) update(Now<<1|1,Mid+1,R,l,r,x);
        pushup(Now);
    }
    ll query(int Now,int L,int R,int l,int r)
    {
        if(l<=L&&r>=R) return sum[Now];
        pushdown(Now,L,R); int Mid=(L+R)>>1; ll res=0;
        if(l<=Mid) res+=query(Now<<1,L,Mid,l,r);
        if(r>Mid) res+=query(Now<<1|1,Mid+1,R,l,r);
        pushup(Now);  return res;
    }
    int main()
    {
        int N,M,opt,L,R,x;
        scanf("%d%d",&N,&M);
        build(1,1,N);
        rep(i,1,M){
            scanf("%d%d%d",&opt,&L,&R);
            if(opt==1){
                scanf("%d",&x);
                update(1,1,N,L,R,x);
            }
            else printf("%lld
    ",query(1,1,N,L,R));
        }
        return 0;
    }

    D .DZY Loves Strings

    题意:给定一个字符串S,然后Q次询问,每次询问给出s和t,|s|,|t|<=4;问包含s和t的最短区间是多长。 |S|<5e4。

    思路:我们可以把S的所有长度为1到4的子串都提出来,(由于不长感觉不会出现碰撞,单hash就够了)。

     然后对于每次询问,我们可以对含s的部分,和含t的部分找最近的地方。即两个集合,在属于不同集合的最近的点对,这里可以用双指针做到线性,单次的复杂度和较小的集合大小有关。  同时,用map记录一下,避免多次出现极端数据。

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2000010;
    map<pii,int>mp;
    vector<int>G[maxn];
    char c[maxn],a[maxn],b[maxn];
    int main()
    {
        int N,Q;
        scanf("%s",c+1);
        N=strlen(c+1);
        rep(i,1,4)
         rep(j,1,N-i+1){
            int t=0;
            rep(k,j,j+i-1) t=t*26+c[k]-'0';
            G[t].push_back(j);
        }
        scanf("%d",&Q);
        while(Q--){
            scanf("%s%s",a+1,b+1);
            int ta=0,tb=0,L1,L2,ans=maxn;
            L1=strlen(a+1); rep(i,1,L1) ta=ta*26+a[i]-'0';
            L2=strlen(b+1); rep(i,1,L2) tb=tb*26+b[i]-'0';
            if(mp.find(pii(ta,tb))!=mp.end()){
                printf("%d
    ",mp[pii(ta,tb)]);
                continue;
            }
            int sz1=G[ta].size(),sz2=G[tb].size();
            int p1=0,p2=0;
            while(p1<sz1&&p2<sz2){
                while(G[tb][p2]<G[ta][p1]){
                    p2++; if(p2>=sz2) break;
                }
                if(p2<sz2)ans=min(ans,max(G[tb][p2]+L2,G[ta][p1]+L1)-G[ta][p1]);
                p1++;
            }
            p1=p2=0;
            while(p1<sz1&&p2<sz2){
                while(G[ta][p1]<G[tb][p2]){
                    p1++; if(p1>=sz1) break;
                }
                if(p1<sz1)ans=min(ans,max(G[ta][p1]+L1,G[tb][p2]+L2)-G[tb][p2]);
                p2++;
            }
            if(ans==maxn) ans=-1;
            mp[pii(ta,tb)]=ans;
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    Linq的一些常见Demo
    有一名员工发现日历已经7天没有翻了,于是他连着翻了7页,7天的总和刚好是138,问这一天是几号?
    20块钱,1块钱1瓶,两个空瓶子可以换一瓶,问最多可以喝几瓶?
    【转】Java编程之字符集问题研究
    Reset / Validate Buffer
    Article Master Data Deviation
    STAD Parameters
    Linux11.2 MySQL常用命令
    Linux11.1 设置更改Mysql的root密码及连接mysql
    Linux5.10 告警系统
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10447494.html
Copyright © 2020-2023  润新知