Codeforces #640(Div.4) Round题解

第一次很顺畅地AK呢,发篇题解纪念一下。

A

思路

直接扫一遍,如果该位上不是 0 0 0,那么它就一定是一个Round Number的首位。然后根据位值原理,后面填 0 0 0就可以啦。

5401 5401 5401中的 4 4 4代表的是 4 4 4 100 100 100,那么一个Round Number就是 4 × 100 = 400 4×100=400 4×100=400

代码

#include 
#define int long long
using namespace std;

signed main()
{
	int t;
	cin>>t;
	
	while (t--)
	{
		int pos=1,cnt=0,ans[10];
		string s;
		cin>>s;
		
		for (int i=s.size()-1;i>=0;i--)
		{
			if (s[i]!='0')  ans[++cnt]=(s[i]-'0')*pos;
			pos*=10;
		}
		cout<<cnt<<endl;
		for (int i=1;i<=cnt;i++)  cout<<ans[i]<<' ';
		cout<<endl;
	}
	return 0;
}

难度: 入门

B

思路

个人认为本题的正解与数论没个P关系。

直接看它能否拆成几个奇数或者几个偶数之和。我们定义两个数组 A , B A, B A,B A A A尝试了奇数的拆分, B B B尝试了偶数的拆分。

那么,对于所有的 1 ≤ i ≤ n − 1 1≤i≤n-1 1in1的正整数 i i i,均将 A i A_i Ai赋为1, B i B_i Bi赋为2(注意输出的所有数必须都是正整数,所以 B i B_i Bi不能赋为0),然后算一算 A n A_n An B n B_n Bn就可以啦。

如果 A n > 0 A_n>0 An0 A n A_n An为奇数,那么就输出Yes与数组 A A A
如果$ B n > 0 B_n>0 Bn>0 B n B_n Bn为偶数,那么久输出Yes与数组 B B B

如果发现前者与后者均不满足,那么就直接打印 N O NO NO

代码

#include 
#define int long long
using namespace std;

int t,n,k;

signed main()
{
	cin>>t;
	while (t--)
	{
		int a[105]={0},b[105]={0};
		cin>>n>>k;
		
		if (n<k)
		{
			cout<<"NO"<<endl;
			continue;
		}
		for (int i=1;i<=k-1;i++)  a[i]=1,b[i]=2;
		a[k]=n-(k-1);
		b[k]=n-2*(k-1);
		
		if (a[k]%2==1&&a[k]>0)
		{
			cout<<"YES"<<endl;
			for (int i=1;i<=k;i++)  cout<<a[i]<<' ';
		}
		else if (b[k]%2==0&&b[k]>0)
		{
			cout<<"YES"<<endl;
			for (int i=1;i<=k;i++)  cout<<b[i]<<' ';
		}
		else cout<<"NO";
		cout<<endl;
	}
	return 0;
}

难度: 普及-

C

怎么全是小学奥数题啊

首先在草稿纸上尝试找到规律。 1 , 2 , 3 … … n − 1 , n + 1 , n + 2 , n + 3 … … 2 n − 1 , 2 n + 1 … … 1,2,3……n-1,n+1,n+2,n+3……2n-1,2n+1…… 1,2,3n1,n+1,n+2,n+32n1,2n+1

规律显然,然后用周期问题搞一搞就可以啦。

#include 
#define int long long
using namespace std;

int t,n,k;

signed main()
{
	cin>>t;
	while (t--)
	{
		int pos=0;
		cin>>n>>k;//4 12
		pos+=(k/(n-1))*n;//16
		
		if (k%(n-1)==0)  pos--;//找到上一个周期的末位
		int now=k%(n-1);//加上剩下的一部分
		if (now<n)  pos+=now;
		else pos+=(now+1);
		
		cout<<pos<<endl;
	}
	return 0;
}

难度: 普及-

D

思路

按照题意模拟即可,但是有些考验代码能力与心态 (TM调试得累死了)

#include 
#define int long long
using namespace std;

int t,n;
int a[200005];

signed main()
{
	cin>>t;
	while (t--)
	{
		cin>>n;
		for (int i=1;i<=n;i++)  cin>>a[i];
		
		int head=0,tail=n+1,cnt=0,alice=0,bob=0,last=0;
		while (head+1<tail)
		{
			cnt++;
			
			if (cnt%2==1)
			{
				int sumv=0;
				for (int i=head+1;i<tail;i++)
				{
					sumv+=a[i];
					if (sumv>last)
					{
						head=i;
						break;
					}
				}
				alice+=sumv;
				
				if (sumv<=last)  break;
				last=sumv;
			}
			else if (cnt%2==0)
			{
				int sumv=0;
				for (int i=tail-1;i>head;i--)
				{
					sumv+=a[i];
					if (sumv>last)
					{
						tail=i;
						break;
					}
				}
				bob+=sumv;
				
				if (sumv<=last)  break;
				last=sumv;
			}
		}
		cout<<cnt<<' '<<alice<<' '<<bob<<endl;
	}
	return 0;
}

难度: 普及-

E

思路

首先,看到 n ≤ 8000 n≤8000 n8000的限制与 1000 m s 1000ms 1000ms的限制,告诉我们正解应该是一个常数小的 O ( n 2 ) O(n^2) O(n2)算法。但是,空间限制只有 64 M B 64MB 64MB,说明我们必须摒弃大空间写法。

于是,我开始考虑,先用 O ( n 2 ) O(n^2) O(n2)的代价找到, 1 − n 1-n 1n中的每个数是否能够成为一个长度不小于2的区间内各数之和。最后扫一遍,数一数这样的 S p e c i a l E l e m e n t s Special Elements SpecialElements即可。


但是怎么用仅仅 O ( n 2 ) O(n^2) O(n2)且小空间的方法来找到所有 S p e c i a l E l e m e n t s Special Elements SpecialElements的值呢?

首先,定义一个 v i s i t e d visited visited数组,其中 v i s i t e d i visited_i visitedi表示 i i i能否成为 S p e c i a l Special Special E l e m e n t Element Element的值。

①不需要大空间。虽然一个区间的和可能会达到 n 2 n^2 n2,但是所有的数均不大于 n n n,也就意味着所有 S p e c i a l Special Special E l e m e n t s Elements Elements的值均不大于 n n n。所以 v i s i t e d visited visited数组的大小开到 n n n就可以啦。

②我们枚举 l l l,然后找 r r r。用一个 s u m v sumv sumv来计算目前 Σ i = l r a i Σ_{i=l}^r a_i Σi=lrai的值,只要 s u m v sumv sumv超过了 n n n就立刻跳出( l → l + 1 l→l+1 ll+1)。对于所有满足要求的 s u m v ( s u m v ≤ n ) sumv(sumv≤n) sumv(sumvn),将 v i s i t e d s u m v visited_{sumv} visitedsumv的值赋为1。


最后扫一遍,看看 v i s i t e d a i visited_{a_i} visitedai是否为1就知道它是否为 S p e c i a l E l m e n t Special Elment SpecialElment啦。数一数即可。

时间复杂度: O ( c 1 n 2 ) O(c_1n^2) O(c1n2) ( c 1 < 1 c1<1 c11)

代码

#include 
#define int long long
using namespace std;

int t,n,a[10005];

signed main()
{
	cin>>t;
	while (t--)
	{
		int tot=0,ans=0;
		bool visited[10005]={0};
		
		cin>>n;
		for (int i=1;i<=n;i++)  cin>>a[i];
		
		for (int i=1;i<=n-1;i++)
		{
			int sumv=a[i];
			for (int j=i+1;j<=n;j++)
			{
				sumv+=a[j];
				
				if (sumv>n)  break;
				else visited[sumv]=1;
			}
		}
		for (int i=1;i<=n;i++)
		{
			if (visited[a[i]]==1)  ans++;
		}
		cout<<ans<<endl;
	}
	return 0;
}

难度: 普及/提高-

F

思路

先凑 a + 1 a+1 a+1 1 1 1,再弄 c + 1 c+1 c+1 0 0 0;然后随便搞一搞弄出 b b b个相邻且不同的位置即可。

注意 a + 1 a+1 a+1个1与 c + 1 c+1 c+1个0之间有一个交界处,那么 b b b就应该减去1。然后从 a + c + 3 a+c+3 a+c+3开始构造,每个数均为上一个数加上1模2的值(相当于0后1,1后0)。

题目保证有解!

代码

#include 
#define int long long
using namespace std;

int t,a,b,c;
int s[1005];

signed main()
{
	cin>>t;
	while (t--)
	{
		int pos=0;
		cin>>a>>b>>c;//0 4 0
		
		if (a!=0)
		{
			for (int i=pos+1;i<=pos+a+1;i++)  s[i]=0;
			pos+=(a+1);
		}
		if (c!=0)
		{
			for (int i=pos+1;i<=pos+c+1;i++)  s[i]=1;
			pos+=(c+1);
		}
		if (b!=0)
		{
			if (a==0||b==0)
			{
				for (int i=pos+1;i<=pos+b+1;i++)  s[i]=(s[i-1]+1)%2;
				pos+=(b+1);	
			}
			else
			{
				for (int i=pos+1;i<=pos+b;i++)  s[i]=(s[i-1]+1)%2;
				pos+=b;
			}
		}
		for (int i=1;i<=a+b+c+1;i++)  cout<<s[i];
		cout<<endl;
	}
	return 0;
}

难度: 普及/提高-

G

思路

如果 n n n为1或2或3,直接输出-1。

如果 n n n为奇数,则这么构造:

n = 5 n=5 n=5时, P = 1 , 3 , 5 , 2 , 4 P={1,3,5,2,4} P=1,3,5,2,4
n = 11 n=11 n=11时, P = 1 , 3 , 5 , 7 , 9 , 11 , 8 , 10 , 6 , 4 , 2 P={1,3,5,7,9,11,8,10,6,4,2} P=1,3,5,7,9,11,8,10,6,4,2

如果 n n n为偶数,则这么构造:

n = 4 n=4 n=4时, P = 2 , 4 , 1 , 3 P={2,4,1,3} P=2,4,1,3
n = 12 n=12 n=12时, P = 2 , 4 , 6 , 8 , 10 , 12 , 9 , 11 , 7 , 5 , 3 , 1 P={2,4,6,8,10,12,9,11,7,5,3,1} P=2,4,6,8,10,12,9,11,7,5,3,1

如果您并不会做这一题,建议您找一下上面我构造的数组的规律。

然后上惨不忍睹的代码~

#include 
#define int long long
using namespace std;

int t,n;
int a[1005];

signed main()
{
	cin>>t;
	while (t--)
	{
		cin>>n;
		if (n==1||n==2||n==3)
		{
			cout<<"-1"<<endl;
			continue;
		}
		if (n%2==0)
		{
			for (int i=1;i<=(n/2);i++)  a[i]=i*2;
			a[(n/2)+1]=a[(n/2)]-3;
			a[(n/2)+2]=a[(n/2)+1]+2;
			for (int i=(n/2)+3;i<=n;i++)
			{
				a[i]=a[i-1]-2;
				if (a[i]==a[(n/2)+1]||a[i]==a[(n/2)+2])  a[i]-=2;
			}
		}
		else if (n%2==1)
		{
			for (int i=1;i<=(n/2)+1;i++)  a[i]=i*2-1;
			a[(n/2)+2]=a[(n/2)+1]-3;
			a[(n/2)+3]=a[(n/2)+2]+2;
			for (int i=(n/2)+4;i<=n;i++)
			{
				a[i]=a[i-1]-2;
				if (a[i]==a[(n/2)+2]||a[i]==a[(n/2)+3])  a[i]-=2;
			}
		}
		for (int i=1;i<=n;i++)  cout<<a[i]<<' ';
		cout<<endl;
	}
	return 0;
}

难度: 普及/提高-

Summary

①本蒟蒻的做题信息:

编号 做题时间 UnAC次数
A 4min 0
B 9min 0
C 11min 0
D 26min 0
E 17min 0
F 35min 4
G 24min 1

②排名: 1320

赶紧膜拜班里一位比我强太多,早就 A K AK AK的神犇。

③总结

做这种水题不能再这么慢了,总是失误——如果这是NOIP的话,我只能AC五题(只有一次提交机会啊)。

我还是太弱了~


撒花✿✿ヽ(°▽°)ノ✿撒花

你可能感兴趣的:(比赛题解,数学)