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

题号题目
T1捡石头
T2魔法药水
T3土地恢复
T4组合数
T5排数字
T6小武的方程
得分443/600

T1

思路

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

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

如图:
在这里插入图片描述

那么转移方程就是:

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;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值