10-14 考试
7点开始考试,第一题傻逼题啊,直接取模过程中加上商就可以了,切掉切掉。
1、光剑
(sword.pas/c/cpp)
【题目描述】
小林和亮亮各有一把光剑,长度分别为 a 和 b,他们拿光剑进行比试。每一
回合,长光剑会砍向短光剑,砍完后,短光剑完好无损,而长光剑则被截成两段,
被截去的长度恰好等于短光剑的长度。若两把光剑长度相等,则比试结束。请问
小林和亮亮将比试多少回合?
【输入格式】
第一行一个整数 T,表示数据组数。
接下来 T 行每行两个正整数 a,b,表示初始状态光剑的长度。
【输出格式】
每组数据输出一个整数,表示能进行几个回合的比试。
【样例输入】
3
1 8
3 7
6 6
【样例输出】
7
4
0
【数据规模】
对于 40%的数据,0 < a,b <= 1000, 1 <= T <= 20;
对于 100%的数据,0 < a,b <= 10^18,1 <= T <= 1000。
code:
#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
inline int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
return sum*f;
}
int t,a,b,ans;
long long work(long long x, long long y){
if(x<y)swap(x, y);
if(y==1)return x-1;
if(x==y)return 0;
if(y==0)return -1;
else return work(y,x%y)+x/y;
}
signed main(){
freopen("sword.in","r",stdin);
freopen("sword.out","w",stdout);
t=read();
for (int i=1;i<=t;i++){
long long x, y;
x=read();y=read();
printf("%lld
",work(x, y));
}
fclose(stdin);
fclose(stdout);
return 0;
}
7点25开始看T2,第一眼感觉很恶心啊,先不管打一个(n^5)的暴搜再说。
打完暴搜立马就想起来昨天ZAGER出的T2,(meeting in the middle) 啊,先搜前三层,再搜后两层,然后lower_bound找相反数就行了,这就完了。
2、化零
(zero.pas/c/cpp)
【题目描述】
小林拥有 2 个集合,亮亮拥有 3 个集合,这五个集合大小相等,且集合中包
含的都是整数。现在他们两个要进行心算比赛。比赛的规则是,将这五个集合放
在一起,谁能先从每个集合中各选一个数,使得选出的五个数之和为 0,谁就获
得胜利。由于这五个集合都不小,而小林和亮亮事先并不知道是否能存在这样的
五个数,因此他们决定先把五个集合都交给你,由你来编程判断是否存在符合条
件的五个数。
【输入格式】
第一行一个整数 N,表示集合的大小。
接下来五行每行 N 个整数,表示这五个集合内的元素。
【输出格式】
如果能找到符合条件的五个数,则输出“YES”,否则输出“NO”。
【样例输入】
3
1 -2 9
-1 2 1
-3 5 1
-1 7 6
-4 -1 -7
【样例输出】
YES
【数据规模】
对于 30%的数据,1 <= N <= 20;
对于 50%的数据,1 <= N <= 100;
对于 100%的数据,1 <= N <= 200,-10^8 <= a[i] <= 10^8,a[i]为集合中元素
code:
#include<iostream>
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
const int wx=8000017;
inline int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
return sum*f;
}
int a[wx],b[wx];
int s[70][4170];
int cnt,tot,num,n;
void dfs(int step,int num){
if(step>=4){
a[++cnt]=num;
return;
}
for(int i=1;i<=n;i++){
dfs(step+1,num+s[step][i]);
}
}
void DFS(int step,int num){
if(step>=3){
b[++tot]=num;
return;
}
for(int i=1;i<=n;i++){
DFS(step+1,num+s[step+3][i]);
}
}
signed main(){
freopen("zero.in","r",stdin);
freopen("zero.out","w",stdout);
n=read();
for(int i=1;i<=5;i++){
for(int j=1;j<=n;j++){
s[i][j]=read();
}
}
dfs(1,0);
DFS(1,0);
sort(a+1,a+1+cnt);
for(int i=1;i<=tot;i++){
int tmp=lower_bound(a+1,a+1+cnt,-b[i])-a;
if(a[tmp]==-b[i]&&tmp<=cnt&&tmp>=1){
printf("YES
");
return 0;
}
}
printf("NO
");
fclose(stdin);
fclose(stdout);
return 0;
}
八点开始肝T3,看起来好难啊,鬼特么2048,不会。
但肯定是DP啊,瞎鸡儿设状态吧,但是感觉复杂度不太对劲啊,,二进制拆位走起来,溜了溜了。
3、2048
(2048.pas/c/cpp)
【题目描述】
小林和亮亮最近正在重温 2048 这款游戏。由于他们的游戏水平高超,觉得
没有什么挑战性,于是决定自己设计一款类似的游戏。
他们设计的游戏中,数字排成了一个线性的序列,每次玩家可以将序列中任
意两个相同的数 a 合并,成为一个新的数 2*a,当合并出 2048 时游戏即获得胜
利。设计完后,他们发现这个游戏比原来的版本更加简单了,于是他们就开始计
算,对于一个给定的长度为 n 的序列,它共有多少子序列可以合并出 2048。请
给出这个数模 998244353 后的值。
【输入格式】
第一行有一个整数 n。
第二行 n 个整数 Ai,表示数列中的数。
【输出格式】
一个整数,即为所求的答案。
【样例输入】
2
2048 2048
【样例输出】
3
【数据规模】
对于 40%的数据,n <= 20;
对于 70%的数据,n <= 500;
对于 100%的数据,1 <= n <= 100000,1 <= Ai <= 2048。
code:
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#define int long long
using namespace std;
const int wx=100017;
const int mod=998244353;
int n,cnt;
int a[20],flag[wx],WX[20];
int a1[wx],a2[wx],a3[wx];
int f[20][wx];
inline int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
return sum*f;
}
int ksm(int a,int b){
int re=1;
while(b){
if(b&1)re=re*a%mod;
a=a*a%mod;
b>>=1;
}
return re;
}
void pre(){
memset(flag,-1,sizeof(flag));
for(int i=0;i<=11;i++){
flag[1<<i]=i;
WX[i]=2048/(1<<i);
}
a1[0]=1;
for(int i=1;i<wx;i++)
a1[i]=a1[i-1]*2%mod;
a3[0]=a2[0]=1;
for(int i=1;i<wx;i++){
a3[i]=a3[i-1]*i%mod;
a2[i]=ksm(a3[i],mod-2);
}
}
void jia(int &a,int b){
a+=b;
if(a>=mod)a-=mod;
}
signed main()
{
freopen("2048.in","r",stdin);
freopen("2048.out","w",stdout);
n=read();pre();
for(int i=0;i<n;i++){
int x;x=read();
if(flag[x]==-1)cnt++;
else a[flag[x]]++;
}
memset(f,0,sizeof f);
int num=min(a[0],WX[0]);
int sum=0,val;
for(int i=0;i<=num;i++){
val=a3[a[0]]*a2[i]%mod*a2[a[0]-i]%mod;
f[0][i]=val;
jia(sum,val);
}
if(WX[0]<a[0])
f[0][WX[0]]=(f[0][WX[0]]+a1[a[0]]-sum+mod)%mod;
for(int i=1;i<=11;i++){
num=min(a[i],WX[i]);
sum=0;
for(int j=0;j<=num;j++){
val=a3[a[i]]*a2[j]%mod*a2[a[i]-j]%mod;
jia(sum,val);
for(int k=0;k<=WX[i-1];k++)
if(f[i-1][k]){
int temp=min(j+k/2,WX[i]);
jia(f[i][temp],val*f[i-1][k]%mod);
}
}
if(a[i]>WX[i]){
val=(a1[a[i]]-sum+mod)%mod;
for(int j=0;j<=WX[i-1];j++)
if(f[i-1][j])
jia(f[i][WX[i]],f[i-1][j]*val%mod);
}
}
printf("%lld
",f[11][1]*a1[cnt]%mod);
return 0;
}
后记总结:
这场考试本来是AK的,但是因为种种原因才考了160分,难受。。。
第二题在debug的时候把(8*10^6)改成了(1*10^6),后四个点全都RE了,也是够傻逼了。。
第三题没写cstdio,直接暴库了,这可爱的dev,真好。
首先自己的题做的不错,但是还是细节上除了致命的问题,所以要像他们说的一样,把心沉下来,继续加油吧。