• Codeforces Round #702 (Div. 3)


    Codeforces Round #702 (Div. 3)

    为什么CD比AB还简单啊(#`O′)

    A. Dense Array

    题意:给你一个数列,数列合法当且仅当相邻的数中较大值除以较小值小于等于(2),你可以添加一些数,让数列合法,问最少添加多少数。

    如果相邻位置合法就过,否则一定是不断除以(2)或不断乘(2),判断一下不合法的位置哪边大然后加数即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 200005
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int T,n,a[N];
    int main()
    {
    	T=read();
    	while(T--)
    	{
    		n=read();
    		int ans=0;
    		for(int i=1;i<=n;i++)
    		{
    			a[i]=read();
    			if(i==1)continue;
    			if(a[i-1]>a[i]&&a[i]*2<a[i-1])
    			{
    				while(a[i-1]>a[i]*2)
    				{
    					a[i-1]=(a[i-1]+1)/2;
    					ans++;
    				}
    			}
    			if(a[i-1]<a[i]&&a[i-1]*2<a[i])
    			{
    				while(a[i-1]*2<a[i])
    				{
    					a[i-1]*=2;
    					ans++;
    				}
    			}
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
    

    B. Balanced Remainders

    题意:给(n)个数((n)(3)的倍数),每次可以让其中的某一个数加(1),你要让(\%3)后余数为(0,1,2)的个数相等,问最少多少次操作。

    大力分类讨论即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 200005
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int T,n,ave,a[3];
    int main()
    {
    	T=read();
    	while(T--)
    	{
    		n=read();ave=n/3;
    		a[0]=a[1]=a[2]=0;
    		for(int i=1;i<=n;i++)a[read()%3]++;
    		if(a[0]==ave&&a[1]==ave)
    		{
    			puts("0");
    			continue;
    		}
    		int sum=0;
    		if(a[0]==ave)
    		{
    			if(a[1]<a[2])printf("%d
    ",a[2]-a[1]);
    			else printf("%d
    ",(a[1]-a[2])/2);
    			continue;
    		}
    		if(a[1]==ave)
    		{
    			if(a[0]<a[2])printf("%d
    ",(a[2]-a[0])/2);
    			else printf("%d
    ",a[0]-a[2]);
    			continue;
    		}
    		if(a[2]==ave)
    		{
    			if(a[0]<a[1])printf("%d
    ",a[1]-a[0]);
    			else printf("%d
    ",(a[0]-a[1])/2);
    			continue;
    		}
    		if(a[0]>ave&&a[1]>ave)
    		{
    			printf("%d
    ",(a[0]-ave)*2+a[1]-ave);
    			continue;
    		}
    		if(a[0]>ave&&a[2]>ave)
    		{
    			printf("%d
    ",(a[2]-ave)*2+a[0]-ave);
    			continue;
    		}
    		if(a[1]>ave&&a[2]>ave)
    		{
    			printf("%d
    ",(a[1]-ave)*2+a[2]-ave);
    			continue;
    		}
    		if(a[0]>ave)
    		{
    			printf("%d
    ",(ave-a[2])*2+ave-a[1]);
    			continue;
    		}
    		if(a[1]>ave)
    		{
    			printf("%d
    ",(ave-a[0])*2+ave-a[2]);
    			continue;
    		}
    		if(a[2]>ave)
    		{
    			printf("%d
    ",(ave-a[1])*2+ave-a[0]);
    			continue;
    		}
    	}
    	return 0;
    }
    

    C. Sum of Cubes

    题意:给一个(10^{12})以内的数,问能否拆成两个正整数的立方和的形式,多组数据。

    由于(10000^3)就已经是(10^{12})了,因此(a)(b)都不会大于(10000),可以把(1-10000)内所有数的立方处理出来,然后枚举(a),在这个数组里二分(b)即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 200005
    #define int long long
    #define MAXN 10000
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int T,n,a[N];
    signed main()
    {
    	T=read();
    	for(int i=1;i<=MAXN;i++)a[i]=i*i*i;
    	while(T--)
    	{
    		n=read();int ff=0;
    		for(int i=1;i<=MAXN;i++)
    		{
    			int x=n-a[i];
    			if(x<=0)break;
    			int pos=lower_bound(a+1,a+MAXN+1,x)-a;
    			//cout<<x<<" "<<pos<<endl; 
    			if(a[pos]==x)
    			{
    				puts("YES");
    				ff=1;
    				break;
    			}
    		}
    		if(!ff)puts("NO");
    	}
    }
    

    D. Permutation Transformation

    题意:给一个排列,每次找这个区间内的最大值的位置作为树根,其左边的区间和右边的区间分别建树,问最后每个点的深度。

    按题意模拟即可,每次找出最大值之后递归建树,最后(dfs)一遍。

    应该有(O(nlog^2 n))的做法,就是用线段树优化找最大值?不过(nleq100),无所谓了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #define N 105
    #define pb push_back
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int T,n,dep[N],a[N];
    vector<int>G[N];
    void divide(int l,int r,int fa)
    {
    	//cout<<l<<" "<<r<<" "<<fa<<endl;
    	if(l>r)return;
    	int pos=l;
    	for(int i=l+1;i<=r;i++)if(a[i]>a[pos])pos=i;
    	G[fa].pb(pos);
    	divide(l,pos-1,pos);divide(pos+1,r,pos);
    }
    void dfs(int x)
    {
    	int siz=G[x].size();
    	for(int i=0;i<siz;i++)
    	{
    		dep[G[x][i]]=dep[x]+1;
    		dfs(G[x][i]);
    	}
    }
    int main()
    {
    	T=read();
    	while(T--)
    	{
    		n=read();
    		int pos=1;
    		for(int i=1;i<=n;i++)a[i]=read(),G[i].clear();
    		for(int i=2;i<=n;i++)if(a[i]>a[pos])pos=i;
    		divide(1,pos-1,pos);divide(pos+1,n,pos);
    		dep[pos]=0;dfs(pos);
    		for(int i=1;i<=n;i++)printf("%d ",dep[i]);
    		puts("");
    	}
    	return 0;
    }
    

    E. Accidental Victory

    题意:(n)个人做游戏,第(i)个人最开始有(a_i)个金币,每次抽出两个人,把金币少的金币给金币多的,金币少的出局,如果一样的话就随机给一个人,问那些人可能留到最后。

    (a_i)值排序后,如果有一个位置(i)(sum ^{i-1} _{j=1} a[j]<a[i])的话,那么所有在(i)之前的位置一定不合法,那么只需要找到最后一个这样的位置即可,前缀和优化一下。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<map>
    #include<algorithm>
    #define N 200005
    #define mp make_pair
    #define int long long
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int T,n,pre[N],a[N],b[N];
    pair<int,int>A[N];
    signed main()
    {
    	T=read();
    	while(T--)
    	{
    		n=read();
    		for(int i=1;i<=n;i++)a[i]=read(),b[i]=0,A[i]=mp(a[i],i);
    		sort(a+1,a+1+n);sort(A+1,A+1+n);
    		for(int i=1;i<=n;i++)pre[i]=pre[i-1]+a[i];
    		int pos=0;
    		for(int i=n;i>=1;i--)
    		{
    			if(a[i]>pre[i-1])
    			{
    				pos=i;
    				break;
    			}
    		}
    		for(int i=pos;i<=n;i++)b[A[i].second]=1;
    		int ans=0;
    		for(int i=1;i<=n;i++)if(b[i])ans++;
    		printf("%d
    ",ans);
    		for(int i=1;i<=n;i++)if(b[i])printf("%d ",i);
    		puts("");
    	}
    }
    
    

    F. Equalize the Array

    题意:给一些数,你要删掉一些数使得剩下的数出现次数相同,问最少删几个。

    一个比较显然的思路就是枚举剩下的数每个出现了几次。

    假设我们考虑最终结果是每个数出现了(i)次,那么出现次数小于(i)的一定都被删了,大于(i)的一定都变成了(i)个,设(pre_i)表示出现次数小于等于(i)的数的个数(sum_i)表示出现次数小于等于(i)的数的种数,那么剩下的数每个出现(i)次的答案数即为:

    [pre[i-1]+(n-pre[i-1])-(sum[n]-sum[i-1])*i ]

    前边是计算直接删掉的,后边是用剩下的个数减去要保留的个数。

    (map)预处理一下(pre)(sum)后枚举(i)即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<map>
    #define N 200005
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int T,n,a[N],pre[N],sum[N];
    map<int,int>mp;
    int main()
    {
    	T=read();
    	while(T--)
    	{
    		n=read();
    		for(int i=1;i<=n;i++)a[i]=read(),mp[a[i]]++,pre[i]=sum[i]=0;
    		for(int i=1;i<=n;i++)
    		{
    			if(mp[a[i]])
    			{
    				pre[mp[a[i]]]++;
    				sum[mp[a[i]]]++;
    				mp[a[i]]=0;
    			}
    		}
    		//for(int i=1;i<=n;i++)printf("######%d %d
    ",sum[i],pre[i]);
    		for(int i=1;i<=n;i++)pre[i]=pre[i-1]+pre[i]*i,sum[i]+=sum[i-1];
    		int ans=n;
    		for(int i=0;i<=n;i++)
    		{
    			//cout<<"!!!!"<<sum[i]<<" "<<pre[i]<<endl;
    			ans=min(ans,pre[i-1]+(n-pre[i-1])-(sum[n]-sum[i-1])*i);
    			//cout<<i<<" "<<pre[i-1]+(n-pre[i-1])-(sum[n]-sum[i-1])*i<<endl;
    		}
    		printf("%d
    ",ans);
    	}
    }
    

    G. Old Floppy Drive

    题意:有一个环,每个位置上有一个数,计数器最开始停在第一个数上,每走到一个新位置上计数器就会加上这个位置上的数,最后一个位置再走一步就是第一个位置,如果计数器的数大于了给定的(x)就会停下,问会走多少步,或者永远也走不完,每次回答一个给定的(x)的答案。

    把询问离线处理,考虑走的过程,实际上在走这么多步之前可以停下的数是一段区间,设走一圈的权值和为(k),由于所有询问都是正数,那么当(kleq0)时,如果第一圈停不下了,那么之后也一定不行,因此直接处理一下即可。

    (k>0)时,考虑我们这个(x)很大的时候,一定是走很多圈之后在停下来,设前缀和最大值为(maxn),可以发现,如果有一个数(y(y>maxn))满足(xequiv y(mod k)),那么(x)(y)走到的位置是一样的,只不过多走了几圈而已,那么我们考虑找到第一个比(maxn)大的满足条件的(y),我们发现这个(y)一定能在两圈之内走完,先算完被减掉的值,排序后直接指针维护即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<map>
    #define N 200005
    #define mp make_pair
    #define int long long
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int T,n,m,a[N],b[N],ans[N],pre[N],tag[N];
    pair<int,int>B[N];
    signed main()
    {
    	T=read();
    	while(T--)
    	{
    		n=read();m=read();
    		for(int i=1;i<=n;i++)a[i]=read();
    		for(int i=1;i<=m;i++)b[i]=read(),B[i]=mp(b[i],i),ans[i]=-1,tag[i]=0;
    		sort(b+1,b+1+m);sort(B+1,B+1+m);
    		int minn=1e15,maxn=-1e15,now=0,pos=1;
    		for(int i=1;i<=n;i++)
    		{
    			now+=a[i];
    			pre[i]=now;
    			if(minn>now)minn=now;
    			if(maxn<now)maxn=now;
    		}
    		if(now<=0)
    		{
    			now=0;
    			for(int i=1;i<=n;i++)
    			{
    				now+=a[i];
    				while(now>=b[pos]&&pos<=m)ans[B[pos].second]=i,pos++;
    			}
    			for(int i=1;i<=m;i++)
    			{
    				if(ans[i]!=-1)printf("%lld ",ans[i]+tag[i]-1);
    				else printf("-1 ");
    			}
    			continue;
    		}
    		for(int i=1;i<=m;i++)
    		{
    			if(b[i]>=maxn)
    			{
    				int xx=b[i];
    				b[i]=(b[i]-maxn)%now+maxn;
    				tag[B[i].second]=((xx-b[i])/now)*n;
    				B[i]=mp(b[i],B[i].second);
    			}
    		}
    		sort(b+1,b+1+m);sort(B+1,B+1+m);
    		now=0;
    		//cout<<"!!"<<b[1]<<endl; 
    		for(int i=1;i<=n;i++)
    		{
    			now+=a[i];
    			while(now>=b[pos]&&pos<=m)ans[B[pos].second]=i,pos++;
    		}
    		for(int i=1;i<=n;i++)
    		{
    			now+=a[i];
    			while(now>=b[pos]&&pos<=m)ans[B[pos].second]=i+n,pos++;
    		}
    		for(int i=1;i<=m;i++)
    		{
    			if(ans[i]!=-1)printf("%lld ",ans[i]+tag[i]-1);
    			else printf("-1 ");
    		}
    		puts("");
    	}
    }
    /*
    1
    2 1
    10000 -5005
    100000000
    */
    
  • 相关阅读:
    使用SocketAsyncEventArgs犯的低级错误
    使用Beetle简单构建高性能Socket tcp应用
    构造BufferWriter和BufferReader实现高效的对象序列化和反序列化
    c#编写高性能Tcp Socket应用注意事项
    文件上传下载流程设计
    识别支点
    interface 与 delegate
    小知识:ADO.NET中的连接池
    解决问题
    IBM把Rational这个软件彻底给毁了
  • 原文地址:https://www.cnblogs.com/szmssf/p/14409146.html
Copyright © 2020-2023  润新知