NEFU 2019 寒假集训新生考试 2020.01.06

Summary

欢迎来到 2020 年 1 月 6 日 举办的 “2019 寒假集训新生考试”
说好的水题为什么突然失踪了?这究竟是人性的泯灭还是道德的沦丧?
表面说的水题实则是一套巨难的题目,成功防止了全体成员 AK o((>ω< ))o
我太菜了,整整4个小时都没有做完 (;´д`)ゞ
下面附上翻车现场 I’m so vegetable
在这里插入图片描述
遇到了一些玄学问题。。。
在这里插入图片描述
19:00 更新完成!终于补完了,太难了 (╯‵□′)╯︵┻━┻
感觉自己 (cai) (de) (yi) (pi)
在这里插入图片描述

Information

No. Title AC/Submit
A 28的因子 19/171
B 陈老师发奖金 91/403
C 小明分蛋糕 74/153
D 神奇的事情发生了 44/172
E jwMM选酒店 2/17
F jwMM的射箭游戏 66/566
G 丹青玩游戏 5/8
H 分糖果 0/47
I 抹发胶 117/155
J 天哥的难题 14/28
K 煊哥的数字游戏 0/15
L 吃辣条 124/156

Problem A: 28的因子 (2101) [19/171]

Tips

本题使用 ios::sync_with_stdio(false); 会 RE
本题使用 ios::sync_with_stdio(false); 会 RE
本题使用 ios::sync_with_stdio(false); 会 RE
重要的事情说三遍!!!
在这里插入图片描述
思路:先将 n 对 4 取余,再对余数进行分析即可得到答案
同时 7 个 4 可以转化成 4 个 7 ,减少数字位数

Code

#include <stdio.h>

int main()
{
	int n,ns,nf,y;
	while(scanf("%d",&n)!=-1)
	{
		ns=0;
		nf=n/4;
		y=n%4;
		if(y==1)
		{
			nf-=5;
			ns+=3; 
		}
		if(y==2)
		{
			nf-=3;
			ns+=2;
		}
		if(y==3)
		{
			nf-=1;
			ns+=1;
		}
		if(ns<0||nf<0)
		{
			printf("xinganheixiong\n");
			continue;
		}
		ns+=nf/7*4;
		nf%=7;
		for(int i=0;i<nf;i++)printf("4");
		for(int i=0;i<ns;i++)printf("7");
		printf("\n");
	}
	return 0;
}

Problem B: 陈老师发奖金 (2077) [91/403]

Tips

简单的结构体排序

Code

#include <bits/stdc++.h>
using namespace std;

struct student
{
	int xh,cyy,sx,yy;
	int num;
}s[100001];

int cmp(student s1,student s2)
{
	if(s1.cyy+s1.sx!=s2.cyy+s2.sx)return s1.cyy+s1.sx>s2.cyy+s2.sx;
	if(s1.yy!=s2.yy)return s1.yy>s2.yy;
	return s1.num>s2.num;
}

int main()
{
	ios::sync_with_stdio(false);
	int n;
	while(cin>>n)
	{
		for(int i=0;i<n;i++)
		{
			cin>>s[i].xh>>s[i].cyy>>s[i].yy>>s[i].sx;
			s[i].num=i+1;
		}
		sort(s,s+n,cmp);
		n=n>4?4:n;
		for(int i=0;i<n;i++)
		{
			cout<<s[i].xh<<" "<<s[i].cyy+s[i].sx<<endl;
		}
	}
	return 0;
}

Problem C: 小明分蛋糕 (2096) [74/153]

Tips

  • 当前蛋糕数与目标蛋糕数 相差5块以上时每次+5/-5
  • 差值为1或2时可以一步解决
  • 差值为3或4时最少需要两步解决
  • “蛋糕数不能为负数” 这个就是用来吓唬人的,没什么用

Code

#include <bits/stdc++.h>
using namespace std;

int main()
{
	ios::sync_with_stdio(false);
	int t,a,b,ans,offset;
	cin>>t;
	while(t--)
	{
		ans=0;
		cin>>a>>b;
		ans+=(abs(a-b)/5);
		offset=(abs(a-b))%5;
		if(offset==4||offset==3)ans+=2;
		else if(offset==2||offset==1)ans++;
		cout<<ans<<endl;
	}
	return 0;
}

Problem D: 神奇的事情发生了 (2090) [44/172]

Tips

用数组模拟,从左到右依次合并 oo,消除 OO 即可

Code

#include <bits/stdc++.h>
using namespace std;

int main()
{
	ios::sync_with_stdio(false);
	char str[101],sta[101],sp;
	while(cin>>str)
	{
		sp=0;
		for(int i=0;i<strlen(str);i++)
		{
			if(sp)
			{
				if(sta[sp-1]=='o'&&str[i]=='o')
				{
					sta[sp-1]='O';
					for(int j=sp-1;j>=1;j--)
					{
						if(sta[j]=='O'&&sta[j-1]=='O')sp-=2;
					}
				}
				else if(sta[sp-1]=='O'&&str[i]=='O')sp--;
				else sta[sp++]=str[i];
			}
			else
			{
				sta[sp++]=str[i];
			}
		}
		for(int i=0;i<sp;i++)
		{
			cout<<sta[i];
		}
		cout<<endl;
	}
	return 0;
}

Problem E: jwMM选酒店 (2083) [2/17]

Tips

与洛谷 P1311 选择客栈 相同,最开始提交洛谷 AC 代码没有通过
原来是数据范围搞的鬼 ≧ ﹏ ≦

2020.01.07 更新:
多出的 最后一组数据会爆int,所以答案要用 long long 存

本题思路:

  • 两个数组分别存放 对应颜色可以住的旅店不可以住的旅店
    可喝奶茶店前方和后方对应颜色的旅店数量
  • 当前旅店楼下奶茶店 不可以喝时对应颜色不可住旅店 +1
  • 当前旅店楼下奶茶店 可以喝时将所有颜色不可住旅店记为可住旅店
    同时 答案加上前方所有可以住的旅店 即可

Code

#include <stdio.h>

int main()
{
	long long ans=0;
	int n,m,pp,color,cost,nl[50]={0},nh[50]={0};
	scanf("%d %d %d",&n,&m,&pp);
	for(int i=0;i<n;i++)
	{
		scanf("%d %d",&color,&cost);
		if(cost>pp)
		{
			nh[color]++;
			ans+=nl[color];
		}
		else
		{
			ans+=nl[color]+nh[color];
			for(int j=0;j<m;j++)
			{
				nl[j]+=nh[j];
				nh[j]=0;
			}
			nl[color]++;
		}
	}
	printf("%lld",ans);
	return 0;
}

Problem F: jwMM的射箭游戏 (2078) [66/566]

Tips

将 x1 y1 分解为多个素数,依次判断能否被 x2-y2 整除
注意:本题需要判断 x2-y2>0

Code

#include <bits/stdc++.h>
using namespace std;

int main()
{
	ios::sync_with_stdio(false);
	int x1,y1,x2,y2,g,ss[1000],sp=0,ok;
	while(cin>>x1>>y1>>x2>>y2)
	{
		g=__gcd(x1,y1);
		ok=sp=0;
		for(int i=2;i<=g;i++)
		{
			if(g%i==0)
			{
				g/=i;
				ss[sp++]=i;
				i=1;
			}
		}
		for(int i=0;i<sp;i++)
		{
			if((x2-y2)>0&&(x2-y2)%ss[i]==0)
			{
				ok=1;
				break;
			}
		}
		if(ok)cout<<"Y"<<endl;
		else cout<<"N"<<endl;
	}
	return 0;
}

Problem G: 丹青玩游戏 (2082) [5/8]

Tips

由于数据量较小,可以使用 二进制枚举 进行处理
情况较复杂,注意判断枚举条件是否成立时不要被绕进去

Code

#include <bits/stdc++.h>
using namespace std;

int main()
{
	ios::sync_with_stdio(false);
	int mapp[11][11]={0},sta[11],ans;
	int n,m,tmp,t,cnt,ok;
	while(cin>>n>>m)
	{
		ans=0;
		memset(mapp,0,sizeof(mapp));
		for(int i=1;i<=m;i++)
		{
			cin>>tmp;
			for(int j=1;j<=tmp;j++)
			{
				cin>>t;
				mapp[i][t]=1;
			}
		}
		for(int i=1;i<=m;i++)
		{
			cin>>sta[i];
		}
		for(int i=0;i<1<<n;i++)
		{
			ok=0;
			for(int j=1;j<=m;j++) //每个灯泡 
			{
				cnt=0; 
				for(int k=1;k<=n;k++) //相关开关 
				{
					if((i&1<<(k-1))&&mapp[j][k])cnt++;
				}
				if(cnt%2!=sta[j])break;
				ok++;
			}
			if(ok==m)ans++;
		}
		cout<<ans<<endl;
	}
	return 0;
}

Problem H: 分糖果 (2100) [0/47]

Tips

2020.01.07 更新:
最开始对题目理解有误,以为要分完所有糖果,后来发现只取两堆糖果
然而还是没有什么思路,于是偷偷看了看巨佬的题解
这里我引用一下 jwMM 引用的 煊哥 的思路 jwMM 题解原文出处

因为每m颗糖果就包装一次所以读入的时候直接读入的每个数对m取模,因为这些才是小a有可能拿到的糖果,然后对处理出来的这个数组排序。
然后就拿第一组输入来说
4 5
1 4 2 3
如果你要找到1的最优解应该是用模数5-1-1=3,然后就找到这个3的位置你可以通过找到4的位置然后往前找一个就是3的位置。如果这个3不存在的话那么最优解就应该是1和数组最后一个数之和的取模结果还有1和4之前一个数的和这两者的最大值。但是如果4往前找一位是你这个数本身的话那就不行,必须再多往前找一位,这里数组不能越界。然后这样循环一遍找到每个数可以得到的ans,然后求其中最大值就可以了。

简单进行一下整理:

  • 因为每m颗糖果为一包所以 读入时可以直接对读入的每个数对m取模
    因为这些才是小a有可能拿到的糖果
  • 然后 对处理出来的数组排序
  • 对于处理后的每个数据 num 的最优解应该是 m-num-1
    例如:对于第一组测试数据 1 的最优解应为 5-1-1=3
  • 如果最优解不存在,最优解就应该是 num 和数组最后一个数之和的取模结果num 和 n-1 之间的一个数的和 这两者的最大值
    例如:对于上面的数据如果 3 不存在那么最优解就是 1 和数组最后一个数之和的取模结果与 1 和 4 之前一个数的和 这两者的最大值。

Code

与题解稍有不同

#include <bits/stdc++.h>
using namespace std;

int main()
{
	int t,n,m,num[100000],tmp,ntf,p,ans;
	scanf("%d",&t);
	while(t--)
	{
		ans=0;
		scanf("%d %d",&n,&m);
		for(int i=0;i<n;i++)
		{
			scanf("%d",&tmp);
			num[i]=tmp%m;
		}
		sort(num,num+n);
		for(int i=0;i<n;i++)
		{
			ntf=m-num[i]-1; //这里直接查找了要找的数
			p=lower_bound(num,num+n,ntf)-num;
			if(p>0&&p-1!=i&&(num[i]+num[p-1])%m>ans)
				ans=(num[i]+num[p-1])%m; //判断前一位与第i位和
			if(p!=i&&(num[i]+num[p])%m>ans)
				ans=(num[i]+num[p])%m; //判断本位与第i位和
			if(p<n-1&&p+1!=i&&(num[i]+num[p+1])%m>ans)
				ans=(num[i]+num[p+1])%m; //如果数字有重复判断下一个
			if(i!=n-1) //判断数组最后一位与第i位
				ans=(num[i]+num[n-1])%m>ans?(num[i]+num[n-1])%m:ans;
		}
		printf("%d\n",ans);
	}
	return 0;
}

Problem I: 抹发胶 (2088) [117/155]

Tips

数据量较小,暴力出奇迹 ~

Code

#include <bits/stdc++.h>
using namespace std;

int main()
{
	ios::sync_with_stdio(false);
	int t,n,num[100],ans[100];
	cin>>t;
	while(t--)
	{
		cin>>n;
		memset(ans,0,sizeof(ans));
		for(int i=0;i<n;i++)
		{
			cin>>num[i];
		}
		ans[0]=0;
		for(int i=1;i<n;i++)
		{
			for(int j=0;j<i;j++)
			{
				if(num[j]<num[i])ans[i]++;
			}
		}
		for(int i=0;i<n;i++)
		{
			if(i!=0)cout<<" ";
			cout<<ans[i];
		}
		cout<<endl;
	}
	return 0;
}

Problem J: 天哥的难题 (2085) [14/28]

Tips

先对题中所给条件进行分析:

  • 使 AB 满足 A+B=A|B 说明应 把一个数的二进制位往另一个数对应二进制位为 0 的地方加
  • 因此问题转化为 获得 N 中二进制位为 0 的位数
  • N=2M,M≤109,2的M次幂为N,让A和B都小于N
  • 可以发现 M 本身即为 N 中二进制位为 0 的位数

对于每一个二进制位都有如下 3 种情况:

  • 都为0(相加以后不变)
  • A为1 B为0 (相当于直接相加)
  • A为0 B为1 (也相当于直接相加)

因此最终答案即为 3M
再利用 快速幂算法 计算出最终答案即可
注意:本题快速幂需要使用 long long 存储数据

Code

#include <bits/stdc++.h>
using namespace std;

long long ksm(long long a,long long b,long long c)
{
	long long ret=1;
	while(b>0)
	{
		if(b&1)ret=ret*a%c;
		a=a*a%c;
		b>>=1;
	}
	return ret;
}

int main()
{
	ios::sync_with_stdio(false);
	int n,m,b0=0,a,c,ans;
	while(cin>>m)
	{
		cout<<ksm(3,m,1e9+7)<<endl;
	}
	return 0;
}

Problem K: 煊哥的数字游戏 (2084) [0/15]

Tips

2020.01.07 更新:
依然是一道巨难的数学题,真是让熊头大 ~
于是我又双叒叕光明正大的去偷窥题解了 ╰( ̄ω ̄o)

简单整理一下思路:

  • 观察题中所给公式 a1+a2+…+am+b = 2*(a1 ⊕ a2 ⊕ … ⊕ am ⊕ b)
    整理得到 a1+a2+…+am + b = 2*(a1 ⊕ a2 ⊕ … ⊕ am) ⊕ 2*b
  • 设 sum = a1+a2+…+am yh = 2*(a1 ⊕ a2 ⊕ … ⊕ am)
    方程转化为 sum + b = yh ⊕ 2*b
  • 想办法使 sum = yh ,即 使 sum 与 yh 的各二进制位对应相等
  • 当 sum 与 yh 不同时,利用积分的思想每次处理一个二进制位,
    模拟等式左右两侧 +b 和 ⊕ 2*b 的过程 直到 sum 与 yh 相等
  • 其中由于异或 2*b 难以处理,因此 等式右边直接异或 tmp
    等式左边 +b 时 + tmp/2 使等式成立
  • 当 sum 与 yh 相同时,用处理后的 sum 减去 sum 的初始值 即可

注意:位运算结果必须强制转换为 long long,否则会 WA

Code

#include <bits/stdc++.h>
using namespace std;

int main()
{
	long long sum=0,yh=0,ori,i=0,tmp; 
	int m;
	scanf("%d",&m);
	while(m--)
	{
		scanf("%d",&tmp);
		sum+=tmp;
		yh^=tmp;
	}
	yh*=2;
	ori=sum;
	while(sum!=yh)
    {
    	i++;
    	tmp=(long long)1<<i; //此处必须强制转换为long long
        if(sum%tmp!=yh%tmp)
        {
            sum+=tmp>>1;
            yh^=tmp;
        }
    }
	printf("%lld",sum-ori);
	return 0;
}

Problem L: 吃辣条 (2102) [124/156]

Tips

签到 (shui) 题,直接排序输出

Code

#include <bits/stdc++.h>
using namespace std;

int main()
{
	ios::sync_with_stdio(false);
	int n,num[100];
	while(cin>>n)
	{
		for(int i=0;i<n;i++)
		{
			cin>>num[i];
		}
		sort(num,num+n);
		cout<<num[n-2]<<" "<<num[1]<<endl;
	}
	return 0;
}
发布了32 篇原创文章 · 获赞 104 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/csg999/article/details/103866108