CoduckCSP-J入门级复赛模拟2补题
一、题面
【T1】下棋(chess)
【T2】汪洋(BigWater)
【T3】删数(delnum)
【T4】平分糖果(candy)
二、考试过程
考试经历
【T1】下棋(chess)
第一题考试觉得很简单(不过差点输入错误,幸亏检查出来了,差点爆0),没注意数据大小,未开long long
【T2】汪洋(BigWater)
看到这个题第一时间没看数据,结果写了个DFS,但是可能有小问题,没有拿分,后来一想前缀和确实能解决
【T3】删数(delnum)
没有思路,三层暴力,极限20分
【T4】平分糖果(candy)
没有思路,直接骗分,极限15分
考试思路
【T1】下棋(chess)
结构体做,正常模拟(但要注意开long long)
【T2】汪洋(BigWater)
这是个图,用DFS做(但没做对且时间超限)
【T3】删数(delnum)
三层暴力循环(but时间超限)
【T4】平分糖果(candy)
没思路,骗分(或者说用特殊情况完成部分分获取)
三、考试源代码
给大家看看蒟蒻的考试代码
//chess
#include<bits/stdc++.h>
using namespace std;
int n;
struct node{
int a,b,c,id,sum;
}ch[100010];
bool cmp(node x,node y)
{
if(x.sum==y.sum) return x.id<y.id;
return x.sum>y.sum;
}
int main()
{
// freopen("chess.in","r",stdin);
// freopen("chess.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&ch[i].c,&ch[i].b,&ch[i].a);
ch[i].id=i;
ch[i].b+=ch[i].c/3;
ch[i].c%=3;
ch[i].a+=ch[i].b/3;
ch[i].b%=3;
ch[i].sum=18*ch[i].a+3*ch[i].b+ch[i].c;
}
sort(ch+1,ch+n+1,cmp);
for(int i=1;i<=n;i++)
printf("%d ",ch[i].id);
return 0;
}
//BigWater
#include<bits/stdc++.h>
using namespace std;
int n,ans;
int a[1010][1010];
int dx[]={0,0,1,-1};
int dy[]={-1,1,0,0};
bool vis[1010][1010];
void dfs(int x,int y,int k,int sum)
{
if(vis[x][y]||x>n||x<1||y>n||y<1) return;
if(x==2&&y==1){
if(k==2||k==3)
ans=max(ans,sum);
return;
}
vis[x][y]=1;
int sx=x+dx[k];
int sy=y+dy[k];
dfs(sx,sy,k,sum+a[sx][sy]);
sx=x+dx[(k+1)%4];
sy=y+dy[(k+1)%4];
dfs(sx,sy,(k+1)%4,sum+a[sx][sy]);
vis[x][y]=0;
}
int main()
{
// freopen("BigWater.in","r",stdin);
// freopen("BigWater.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
dfs(1,1,0,100);
printf("%d",ans);
return 0;
}
/*5
0 -3 8 -2 3
3 -1 -3 -10 -6
9 -9 -6 10 -7
-2 -4 -9 6 -10
-1 8 -7 10 -5*/
//delnum
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+100;
int n,a[N],q,x,c[1000010];
int vis[N];
int b[N];
void fun(int x)
{
for(int i=1;i<=n;i++) b[i]=a[i];
for(int i=1;i<=x/n;i++)
{
for(int j=1;j<=n;j++)
{
int cnt=0;
for(int k=1;k<=x;k++)
{
if(vis[k]==0)
cnt++;
if(cnt==a[j])
{
b[j]=k;
break;
}
}
}
for(int j=1;j<=n;j++) vis[b[j]]=i;
}
}
int main()
{
// freopen("delnum.in","r",stdin);
// freopen("delnum.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
scanf("%d",&q);
fun(5100);
while(q--)
{
scanf("%d",&x);
printf("%d\n",vis[x]);
}
return 0;
}
//平分糖果
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+100;
int a[6];
int cnt,g[N];
bool dfs(int len,int x)
{
for(int i=x;i<=cnt;i++)
{
if(len<a[i]) return 0;
if(dfs(len-a[i],i+1)) return 1;
}
}
int main()
{
// freopen("candy.in","r",stdin);
// freopen("candy.out","w",stdout);
int pos=0;
while(1)
{
bool flag=0;
long long sum=0;
for(int i=1;i<=6;i++)
{
scanf("%d",a+i);
if(a[i]) flag=1;
sum+=a[i]*i;
for(int j=1;j<=a[i];j++)
{
g[+cnt]=i;
}
}
if(!flag) break;
pos++;
printf("Collection #%d:\n",pos);
if(dfs(sum/2,1)||sum%2!=0) printf("Can be divided.\n\n");
else printf("Can't be divided.\n\n");
}
return 0;
}
四、思路讲解
【T1】用结构体模拟,直接根据题目模拟机即可(注意开long long)
【T2】用两个一维前缀和或两个二维前缀和计算每个点(注意最后要回到(1,1)的位置上)
【T3】当x小于a[]的最大值时,每次删数会让a[]缩小n,当小于最大值时,会缩小n-比x大的a[]数
【T4】二进制优化多重背包
五、AC代码
接下来是AC代码
//chess
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
struct node{
int a,b,c,id,sum;
}ch[100010];
bool cmp(node x,node y)
{
if(x.sum==y.sum) return x.id<y.id;
return x.sum>y.sum;
}
signed main()
{
// freopen("chess.in","r",stdin);
// freopen("chess.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&ch[i].c,&ch[i].b,&ch[i].a);
ch[i].id=i;
ch[i].b+=ch[i].c/3;
ch[i].c%=3;
ch[i].a+=ch[i].b/3;
ch[i].b%=3;
ch[i].sum=18*ch[i].a+3*ch[i].b+ch[i].c;
}
sort(ch+1,ch+n+1,cmp);
for(int i=1;i<=n;i++)
printf("%d ",ch[i].id);
return 0;
}
//BigWater
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1005;
int n,a[N][N],r[N][N],c[N][N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&a[i][j]);
r[i][j]=r[i][j-1]+a[i][j];
c[i][j]=c[i-1][j]+a[i][j];
}
}
int ans=-0x3f3f3f3f;
for(int i=2;i<=n;i++)
{
for(int j=2;j<=n;j++)
{
ans=max(ans,r[1][j-1]+c[i-1][j]+r[i][j]+c[i-1][1]);
}
}
printf("%d",ans+100);
return 0;
}
//delnum
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+100;
int n,a[N],q,x;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
scanf("%d",&q);
while(q--)
{
scanf("%d",&x);
int ans=0,flag=0;
for(int i=n;i>=1;i--)
{
if(a[i]<x)
{
ans+=(x-a[i])/i;
x=a[i]+(x-a[i])%i;
if(x>a[i])
{
x-=i;
ans++;
}
}
if(a[i]==x)
{
ans++;
flag=1;
break;
}
}
if(flag) printf("%d\n",ans);
else puts("0");
}
return 0;
}
//candy
#include<bits/stdc++.h>
using namespace std;
const int N=1.2e5+100;
int mark,a[10];
bool f[N];
int main()
{
while(~scanf("%d%d%d%d%d%d",a+1,a+2,a+3,a+4,a+5,a+6))
{
int m=a[1]+a[2]*2+a[3]*3+a[4]*4+a[5]*5+a[6]*6;
if(!m) break;
else for(int i=1;i<=m;i++) f[i]=0;
printf("Collection #%d:\n",++mark);
f[0]=1;
for(int i=1;i<=6;i++)
{
for(int k=1;k<=a[i];k<<=1)
{
for(int j=m;j>=i*k;j--)
{
f[j]=f[j]|f[j-i*k];
}
a[i]-=k;
}
if(a[i])
{
for(int j=m;j>=i*a[i];j--)
{
f[j]=f[j]|f[j-i*a[i]];
}
}
}
if(!(m&1)&&f[m>>1]) printf("Can be divided.\n");
else printf("Can't be divided.\n");
}
return 0;
}
六、写在最后
1.写给过去的自己:
普及组也还行
2.写给现在的自己:
还要努力
3.写给未来的自己:
普及正式考试加油