• Educational Codeforces Round 37


    A - Water The Garden

    /*
        给出一排格子,告诉你一些格子上有水,会往两边流动,问流满全部格子需要的时间
    */
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    using namespace std;
    int main(){
        int T,n,m,a[210],d[210],ans;
        scanf("%d",&T);
        while(T--){
            ans=0;
            scanf("%d%d",&n,&m);
            memset(d,0x3f,sizeof(d));
            for(int i=1;i<=m;i++)scanf("%d",&a[i]);
            for(int i=1;i<=n;i++){
            	for(int j=1;j<=m;j++){
            		d[i]=min(d[i],abs(i-a[j])+1);
            	}ans=max(ans,d[i]);
            }    
            printf("%d
    ",ans);
        }return 0;
    }

    B - Tea Queue

    /*
        告诉你n个人来打水的时间和等待到的最迟时间,来的时间相同的话编号小的排前面
        问每个人取到水的时间,如果没取到水,则输出0
    */
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int N=5010; 
    int T,n,l[N],r[N],ans[N];
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            for(int i=1;i<=n;i++)scanf("%d%d",&l[i],&r[i]);
            int nowt=0;
    		for(int i=1;i<=n;i++){
    			if(nowt>r[i]){ans[i]=0;continue;}
            	if(l[i]>=nowt)ans[i]=l[i],nowt=l[i]+1;
    			else ans[i]=nowt,nowt++; 
            }for(int i=1;i<=n;i++)printf("%d%c",ans[i],i==n?'
    ':' ');
        }return 0;
    }

    C - Swap Adjacent Elements

    /*
        告诉你一个a序列,和一个s序列,s序列为1表示这个位置的a序列可以和下一个互换,
        问能否通过随意交换可互换元素将a序列排序
    */
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    int n,a[200010];
    char s[200010];
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        scanf("%s",s+1);s[n]='0';
        for(int i=1;i<n;i++){
            if(s[i]=='1'){
                for(int j=i;j<=n;j++){
                    if(s[j]=='0'){
                        sort(a+i,a+j+1);
                        i=j;
                        break;
                    }
                }
            }
        }
        int flag=1;
        for(int i=1;i<n;i++){
            if(a[i]>a[i+1]){puts("NO");flag=0;break;}
        }if(flag)puts("YES");
        return 0;
    }

    D - Tanks

    /*
        题目大意:给出N个容量无限的桶,每个桶中开始都有一些水,给出一个大小为K的勺子,
        问你能否通过N+5次以内的勺水操作(从一个桶到另一个桶),使得最后能有一个桶中的
        水为V
        题解:我们将所有的桶中的水量对K取模,如果这些值能够取一些相加取模后得到V%K,
        说明答案可行,我们可以用01背包解决这个问题,对于路径输出,我们在做dp的时候记录路径,
        表示这个位置是答案的组成部分,那么根据是否是答案的组成部分,我们将桶分为两部分,
        对于处于同个部分的桶,我们把水全都倒进一个桶中,
        那么最后只要在这两个桶相互倒就可以得到答案
    */
    #include <cstdio>
    #include <algorithm>
    #include <vector>
    using namespace std;
    const int MAXN=5010;
    int N,K,V,S,a[MAXN];
    bool dp[MAXN][MAXN],pre[MAXN][MAXN];
    vector<int> vc[2];
    void Solve(){
        for(int i=1;i<=N;i++)S+=a[i];
        if(S<V){puts("NO");return;}
        dp[0][0]=1;
        for(int i=1;i<=N;i++){
            int x=a[i]%K;
            for(int j=0;j<K;j++)if(dp[i-1][j]){
                dp[i][j]=1; pre[i][j]=0;
                dp[i][(j+x)%K]=1; pre[i][(j+x)%K]=1;
            }
        }if(!dp[N][V%K]){puts("NO");return;}
        int v=V%K;
        for(int i=N;i>0;i--){
            int x=a[i]%K;
            if(pre[i][v]){
                vc[1].push_back(i);
                v=(v-x+K)%K;
            }else vc[0].push_back(i);
        }
        puts("YES");
        sort(vc[0].begin(),vc[0].end());
        sort(vc[1].begin(),vc[1].end());
        for(int k=0;k<2;k++)if(vc[k].size()){
            for(int i=1;i<vc[k].size();i++)printf("%d %d %d
    ",1000000000,vc[k][i],vc[k][0]);
        }
        int x0,x1,s=0;
        for(int i=0;i<vc[1].size();i++)s+=a[vc[1][i]];
        if(!vc[0].size())x1=vc[1][0],x0=vc[1][1];
        else if(!vc[1].size())x1=vc[0][1],x0=vc[0][0];
        else x1=vc[1][0],x0=vc[0][0];
        if(s<V)printf("%d %d %d
    ",(V-s)/K,x0,x1);
        if(s>V)printf("%d %d %d
    ",(s-V)/K,x1,x0);
    }
    int main(){
        scanf("%d%d%d",&N,&K,&V);
        for(int i=1;i<=N;i++)scanf("%d",&a[i]);
        Solve(); 
        return 0;
    }

    E - Connected Components?

    /*
        题目大意:给出一张图,求补图的连通块和其大小
        题解:搜索的理论复杂度O(n^2),显然不行,
        bfs的时候对于已经归入其余连通块的点用并查集进行段无效信息处理,减少搜索树的分支,
        显然经过这样的处理搜索分支的数量下降得非常快,就能顺利解决此题了
    */
    #include <cstdio>
    #include <algorithm>
    #include <queue> 
    using namespace std;
    const int N=200010;
    int f[N],n,m,vis[N],ans,cnt[N];
    vector<int> v[N];
    int sf(int x){return f[x]==x?x:f[x]=sf(f[x]);}
    void bfs(int st){
        queue<int> q;
        q.push(st);
        cnt[++ans]=1;
        while(q.size()){
            int x=q.front();q.pop();f[x]=sf(x+1);
            for(int i=0;i<v[x].size();i++)vis[v[x][i]]=x;
            for(int i=sf(1);i<=n;i=sf(i+1))if(vis[i]!=x){
                cnt[ans]++;
                f[i]=sf(i+1);
                q.push(i);
            }
        }
    }
    int main(){
        while(~scanf("%d%d",&n,&m)){
            ans=0;
            while(m--){
                int x,y;
                scanf("%d%d",&x,&y);
                v[x].push_back(y);
                v[y].push_back(x);
            }
            for(int i=1;i<=n+1;i++)f[i]=i;
            for(int i=1;i<=n;i=sf(i+1))bfs(i);
            printf("%d
    ",ans);
            sort(cnt+1,cnt+ans+1);
            for(int i=1;i<=ans;i++)printf("%d%c",cnt[i],i==ans?'
    ':' ');
        }return 0;
    }

    F - SUM and REPLACE

    /*
        题目大意:给出一个序列,要求维护区间求和,和区间修改操作,
        修改操作是将区间中每个数变为其约数个数
        题解:我们计算一下约数个数发现,D(1)=1,D(2)=2,如果一个区间全是这样的数字的话
        我们就不需要对这个区间进行修改,所以我们只要暴力改数值,当发现一个区间的最大值是1或2时
        我们就停止往下修改
    */
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    const int N=1000010,M=2000010;
    int p[N];
    namespace Segment_Tree{
        int tot;
        struct node{int l,r,a,b;LL mx,val;}T[M];
        void build(int,int);
        void Initialize(int n){
            tot=0;
            build(1,n);
        } 
        void up(int x){
            T[x].val=T[T[x].l].val+T[T[x].r].val;
            T[x].mx=max(T[T[x].l].mx,T[T[x].r].mx);
        }
        void build(int l,int r){
            int x=++tot;
            T[x].a=l;T[x].b=r;T[x].l=T[x].r=T[x].val=T[x].mx=0;
            if(l==r){scanf("%lld",&T[x].val);T[x].mx=T[x].val;return;}
            int mid=(l+r)>>1;
            T[x].l=tot+1;build(l,mid);
            T[x].r=tot+1;build(mid+1,r);
            up(x);
        }
        void change(int x,int a,int b){
            if(T[x].mx==1||T[x].mx==2)return;
            if(T[x].a==T[x].b){T[x].mx=T[x].val=p[T[x].val];return;}
            int mid=(T[x].a+T[x].b)>>1;
            if(mid>=a&&T[x].l)change(T[x].l,a,b);
            if(mid<b&&T[x].r)change(T[x].r,a,b);
            up(x);
        }
        LL query(int x,int a,int b){
            if(T[x].a>=a&&T[x].b<=b)return T[x].val;
            int mid=(T[x].a+T[x].b)>>1; LL res=0;
            if(mid>=a&&T[x].l)res+=query(T[x].l,a,b);
            if(mid<b&&T[x].r)res+=query(T[x].r,a,b); 
            return res;
        } 
    }
    int n,m,t,l,r;
    int main(){
        for(int i=1;i<=1000000;i++){
            for(int j=i;j<=1000000;j+=i)p[j]++;
        }
        scanf("%d%d",&n,&m);
        Segment_Tree::Initialize(n);
        while(m--){
            scanf("%d%d%d",&t,&l,&r);
            if(t==1)Segment_Tree::change(1,l,r);
            else printf("%lld
    ",Segment_Tree::query(1,l,r));
        }return 0;
    }

    G - List Of Integers

    /*
        题目大意:求出比x大的和p互质的第k大的数
        题解:我们二分答案,将题目转化为判定区间内和一个数互质的数是否大于k
        求区间内和一个数互质的数的个数我们可以用容斥来解决,将这个数的约数筛选出来,
        然后容斥区间内约数个数出现的次数即可
    */
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N=10000010;
    typedef long long LL;
    #define pw(x) (1LL<<x)
    int T;
    LL x,y,k,p;
    LL cal(LL x,vector<LL> &p){
        LL res=0;
        int n=p.size();
        for(int i=0;i<pw(n);i++){
            LL t=1,f=1;
            for(int j=0;j<n;j++)if(i>>j&1)t*=p[j],f*=-1;
            res+=f*(x/t);
        }return res;
    }
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%lld%lld%lld",&x,&p,&k);
            vector<LL> f;
            for(LL i=2;i*i<=p;i++)if(p%i==0){
                f.push_back(i);
                while(p%i==0)p/=i;
            }
            if(p>1)f.push_back(p);
            k+=cal(x,f);
            LL l=1LL,r=1000000000000LL,ans;
            while(l<=r){
                LL mid=(l+r)/2;
                if(cal(mid,f)>=k)ans=mid,r=mid-1;
                else l=mid+1;
            }printf("%lld
    ",ans);
        }return 0;
    }
  • 相关阅读:
    汉语-词语:判断(逻辑学名词)
    汉语-词语:判断
    汉语-成语:生死有命,富贵在天
    汉语-成语:知人善任
    汉语-成语:真才实学
    太阳系-八大行星:地球
    汉语-词语:宇宙(哲学定义)
    汉语-词语:毅行
    汉语-词语:活在当下
    使用网络监视器(IRSI)捕捉和分析协议数据包
  • 原文地址:https://www.cnblogs.com/forever97/p/edu37.html
Copyright © 2020-2023  润新知