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;
}