欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

2020.10.29【CSP-J/S】普及组模拟赛总结

程序员文章站 2022-05-12 12:28:13
...
题号 题目
T1 捡石头
T2 魔法药水
T3 土地恢复
T4 组合数
T5 排数字
T6 小武的方程
得分 443/600

T1

思路

我们先用桶来记录每个石子的位置,然后分类讨论:

  1. 小武走到第一个,小林走到第二个
  2. 小武走到第二个,小林走到第一个

如图:
2020.10.29【CSP-J/S】普及组模拟赛总结

那么转移方程就是:

a n s + = m i n ( a b s ( a [ i + 1 ] [ 1 ] − a [ i ] [ 1 ] ) + a b s ( a [ i + 1 ] [ 2 ] − a [ i ] [ 2 ] ) , ans+=min(abs(a[i+1][1]-a[i][1])+abs(a[i+1][2]-a[i][2]), ans+=min(abs(a[i+1][1]a[i][1])+abs(a[i+1][2]a[i][2]),

a b s ( a [ i + 1 ] [ 2 ] − a [ i ] [ 1 ] ) + a b s ( a [ i + 1 ] [ 1 ] − a [ i ] [ 2 ] ) ) abs(a[i+1][2]-a[i][1])+abs(a[i+1][1]-a[i][2])) abs(a[i+1][2]a[i][1])+abs(a[i+1][1]a[i][2]))

代码

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
long long a[100010][2],b[100010];
long long n,s,ans;
int main()
{
	cin>>n;
	for(int i=1; i<=2*n; i++)
	 {
	 	scanf("%d",&s);
	 	if(b[s]==1)
	 	 {
	 	 	b[s]++;
	 	 	a[s][1]=i;
		 }
		else
		  a[s][0]=i,b[s]++;
	 }
	ans=a[1][0]+a[1][1]-2;
	for(int i=1; i<n; i++)
	   ans=ans+min(abs(a[i+1][0]-a[i][0])+abs(a[i+1][1]-a[i][1]),abs(a[i+1][0]-a[i][1])+abs(a[i+1][1]-a[i][0]));
	cout<<ans;
	return 0;
}

T2

思路

首先统计出每个 L i L_i Li 的个数。
因为 2 x + 2 x = 2 x + 1 2^x+2^x=2^{x+1} 2x+2x=2x+1
所以我们可以不断合并每个 L i L_i Li
L i L_i Li 个数是奇数时,合并 L i − 1 L_i-1 Li1 个,将剩下的那个 L i L_i Li 用一个瓶子装。
L i L_i Li 个数是偶数时,合并 L i L_i Li 个。

代码

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
long long x,a[1001010];
long long n,ans;
int main()
{
	cin>>n;
	for(int i=1; i<=n; i++)
	 {
	 	scanf("%d",&x);
	 	a[x]++;
	 }
	for(int i=0; i<=1001008; i++)
	 {
	 	a[i+1]+=a[i]/2;
	 	ans=ans+a[i]%2;
	 }
	cout<<ans;
	return 0;
}

T3

思路

本题可以直接暴力查询。
每次从一个完整的区间里选一个最小的数(完整的意思是没有零的区间),
并减去次数,统计答案,直到数列全部变成零。

代码

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n,j=1,k,minn=2147483647,ans;
int a[100010];
int main()
{
	cin>>n;
	for(int i=1; i<=n; i++)
	   scanf("%d",&a[i]);
	while(j<=n)
	 {
	  	if(a[j]==0)
	  	 {
	  	 	j++;
	  	 	continue;
		 }
		k=j;
		minn=2147483647;
		while(a[k]>0)
		 {
		 	minn=min(a[k],minn);
		 	k++;
		 }
		k=j;
		while(a[k]>0)
		 {
		 	a[k]-=minn;
		 	k++;
		 }
		ans+=minn;
	 }
	cout<<ans;
	return 0;
}

T4

思路

此题是原题,具体解释参考这篇博客(组合数问题)

代码

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
long long sum[2510][2510],yh[2510][2510];
long long t,k,n,m;
void yhsj()
{
	yh[0][0]=1,yh[1][0]=1,yh[1][1]=1;
	for(int i=2; i<=2000; i++)
	 {
	 	yh[i][0]=1;
        for(int j=1; j<=i; j++)
         {
         	yh[i][j]=(yh[i-1][j-1]+yh[i-1][j])%k;
         	if(yh[i][j]==0)
         	  sum[i][j]=1;
         	sum[i][j]=sum[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
		 }
		sum[i][i+1]=sum[i][i];
	 }
}
int main()
{
	cin>>t>>k;
	yhsj();
	while(t--)
	 {
	 	cin>>n>>m;
	 	if(m>n)
	 	  cout<<sum[n][n]<<endl;
	 	else
	 	  cout<<sum[n][m]<<endl;
	 }
	return 0;
}

T5

思路

用贪心的思想,每次找到一个没选的数,
看以它能不能找出 m m m 个数满足连续需求,如果不能就直接 f a l s e false false

代码

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
long long T,n,m,bj,mm,k,w,x;
long long a[100010];
int main()
{
	cin>>T;
	while(T--)
	 {
	 	w=0;
	 	cin>>n>>m;
	 	if(n%m!=0)
	 	 {
	 	 	cout<<"false"<<endl;
	 	 	continue;
		 }
	 	for(int i=1; i<=n; i++)
	 	   scanf("%lld",&a[i]);
	 	sort(a+1,a+1+n);
	    for(int i=1; i<=n/m; i++)
	     {
	        for(int j=1; j<=n; j++)
	         if(a[j]>=0)
	          {
	          	bj=a[j];
	          	a[j]=-1;
	          	break;
			  }
			mm=1,k=0,x=1;
	     	while(mm<m&&k<=n)
	     	 {
	     	 	k++;
	     	 	if(a[k]==-1||a[k]==bj)
	     	 	  continue;
	     	 	if(a[k]==bj+x)
	     	 	  a[k]=-1,mm++,x++;
			 }
			if(k>n&&mm<m)
			 {
			 	cout<<"false"<<endl;
			 	w=1;
			 	break;
			 }
		 }
		if(w==1)
		  continue;
		for(int j=1; j<=n; j++)
		 if(a[j]!=-1)
		  {
		  	cout<<"false"<<endl;
		  	w=1;
		  	continue;
		  }
		if(w==0)
		  cout<<"true"<<endl;
	 }
	return 0;
}

T6

思路

首先,因为 x ∣ y x|y xy 一定小于 x + y x+y x+y,所以必须满足 B > = A B>=A B>=A 的情况。
其次,我们让 x x x 等于 A A A,那么 B − A B-A BA 就是 y y y 的值(在满足第二个条件的情况下)
这时就让 A A A B − A B-A BA 异或一下,看等不等与 A A A 就可以了。

代码

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
long long t,a,b;
int main()
{
	cin>>t;
	while(t--)
	 {
	 	cin>>a>>b;
	 	if((b>=a)&&(((b-a)|a)==a))
	 	  cout<<"Possible"<<endl;
	 	else
	 	  cout<<"Impossible"<<endl;
	 }
	return 0;
}
相关标签: 计划and比赛