2019.08.01比赛总结
程序员文章站
2022-03-14 19:20:50
...
本文放代码仅供已做出本题的人交流参考使用,禁止抄袭!!!
今天比赛凉了~~~
最后一题把给卡爆了,到现在还在
【题解】
比赛时觉得是一道博弈论的题目,然而却给出了整个矩阵,所以和其它的博弈论题目不一样,赛时没有思路,于是判断如果整个矩阵的数全是偶数且也为偶数,则输出,否则输出竟然还有。正解是我感觉是递推,设表示前行列的矩阵是否存在必胜策略,那么易得如果必败,且第行前个数的和是偶数,则必胜。对于同理。
另:对于一段数的和需使用二维前缀和,一开始判断如果是偶数,则必胜,否则必败。
代码:
#include<cstdio>
#include<cstring>
#define N 1010
using namespace std;
int t,n;
int f[N][N],sum[N][N],a[N][N];
int main()
{
scanf("%d",&t);
++t;
while (--t)
{
memset(sum,0,sizeof sum);
memset(f,0,sizeof f);
scanf("%d",&n);
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
scanf("%d",&a[i][j]),sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+a[i][j];
if (a[1][1]%2==0) f[1][1]=1;
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
{
if (!f[i-1][j] && (sum[i][j]-sum[i-1][j])%2==0) f[i][j]=1;
if (!f[i][j-1] && (sum[i][j]-sum[i][j-1])%2==0) f[i][j]=1;
}
if (f[n][n]) printf("W\n");
else printf("L\n");
}
return 0;
}
比赛时没有思路,对于如何判断相邻的数不知所措,所以最后提交了输出的程序,果不其然拿了分。正解是暴力模拟,用一个数组,表示与编号为的数相邻的第个数是什么,首先要预处理出数组,其中有几个点要注意,要前后连相邻边,每一层的环要首尾连相邻边,如果你在判外层相邻的时候先自增了,那么最后记得。
代码:
#include<cstdio>
#include<cstring>
#define N 10010
using namespace std;
int n,a,begin,end,t,now;
int c[N][10],cnt[N],tot[N],bz[10],cc[N];
inline int getnum()
{
int o=0x3f3f3f3f,w;
for (int I=1;I<=5;++I) if (o>tot[I] && !bz[I]) o=tot[I],w=I;
return w;
}
void getans()
{
begin=2,end=7,t=2;
tot[1]=cc[1]=1;
for (int i=2;i<=7;++i) c[1][++cnt[1]]=i,c[i][++cnt[i]]=1;
for (int i=2;i<=10005;++i)
{
c[i][++cnt[i]]=i+1;
c[i+1][++cnt[i+1]]=i;
memset(bz,0,sizeof bz);
for (int ii=1;ii<=cnt[i];++ii) bz[cc[c[i][ii]]]=1;
cc[i]=getnum();
++tot[cc[i]];
if (i==begin) c[i][++cnt[i]]=end,c[end][++cnt[end]]=i,begin=end+1,end+=t*6,++t,now=begin;
while (cnt[i]<6) c[i][++cnt[i]]=now,c[now][++cnt[now]]=i,++now;
--now;
}
}
int main()
{
memset(c,0,sizeof c);
memset(cnt,0,sizeof cnt);
memset(tot,0,sizeof tot);
memset(cc,0,sizeof cc);
scanf("%d",&n);
getans();
while (n--)
{
scanf("%d",&a);
printf("%d\n",cc[a]);
}
return 0;
}
比赛时一开始自然地想先拿暴力分,打了个的暴力。后来被“余数”二字开导,想到用一个桶存该序列的前缀和的余数,因为在同一个桶中的数两两为左右端点都可以组成一个合法的子序列,即第个桶的贡献是,表示第个桶中数的个数,证明如下:
设到的前缀和的值为
若到的前缀和的值也为
则原序列中的值为
因为个数中取出个数的组合种数是,所以第个桶的贡献是
另:最后的答案要加上,因为对于前缀和能整除的,自己也能为一个子序列。
十年一场空,不开见祖宗
代码:
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
ll t,k,n,a,now,ans;
ll cnt[1000010];
int main()
{
scanf("%lld",&t);
while (t--)
{
memset(cnt,0,sizeof cnt);
now=ans=0;
scanf("%lld %lld",&k,&n);
for (int i=1;i<=n;++i) scanf("%lld",&a),now=(now+a)%k,cnt[now]++;
for (int i=0;i<k;++i) ans+=cnt[i]*(cnt[i]-1)/2;
printf("%lld\n",ans+cnt[0]);
}
return 0;
}
明天继续加油!!!