大概,接下来半年都不怎么打比赛了(大哭)
这场比赛自己打得并不好,似乎也是冥冥中的必然吧。
先看C:
题意:在n*n上放置多米诺骨牌,不重叠,不要求全覆盖。
对于每一行,我们记它的值为在这一行的方块上有覆盖的多米诺骨牌的个数,列同理。我们要求这些数要相同,且至少放置一块多米诺骨牌。
行的话输出-1,不行的话输出方案。
解法:3,4,5,7构造出来
3,4比较容易手玩,但5,7博主这垃圾水平,绝对玩不出来。
如果有读者有算法方法,欢迎在下面评论。
然后4,5,7的时候构造满足每行每列都是3。
于是我们得到了一个这样的算法:
先特判是3的倍数的n
然后判可以表示成的n
然后你发现只有n=1,2会判成-1,显然
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
#define Maxn 1005
bool f[Maxn];
int pre[Maxn];
char ch[Maxn][Maxn];
char c3[10][10]={
{'a','a','.'},
{'.','.','a'},
{'.','.','a'}
};
char c4[10][10]={
{'a','a','b','c'},
{'d','d','b','c'},
{'b','c','a','a'},
{'b','c','d','d'}
};
char c5[10][10]={
{'a','a','b','b','a'},
{'b','c','c','.','a'},
{'b','.','.','c','b'},
{'a','.','.','c','b'},
{'a','b','b','a','a'}
};
char c7[10][10]={
{'a','a','b','b','c','c','.'},
{'d','d','.','d','d','.','a'},
{'.','.','d','.','.','d','a'},
{'.','.','d','.','.','d','b'},
{'d','d','.','d','d','.','b'},
{'.','.','d','.','.','d','c'},
{'.','.','d','.','.','d','c'}
};
inline void output(){
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j)printf("%c",ch[i][j]);
puts("");
}
}
int main(){
scanf("%d",&n);
f[0]=true;
for(int i=1;i<=n;++i){
if(i>=4&&f[i-4]){
f[i]=true;
pre[i]=4;
}
if(i>=5&&f[i-5]){
f[i]=true;
pre[i]=5;
}
if(i>=7&&f[i-7]){
f[i]=true;
pre[i]=7;
}
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)ch[i][j]='.';
if(n%3==0){
for(int i=1;i<=n;i+=3)
for(int j=0;j<3;++j)
for(int k=0;k<3;++k)
ch[i+j][i+k]=c3[j][k];
output();
}else if(f[n]){
int tmp=n;
while(n){
if(pre[n]==4){
for(int i=n-3;i<=n;++i)
for(int j=n-3;j<=n;++j)
ch[i][j]=c4[i-n+3][j-n+3];
}
if(pre[n]==5){
for(int i=n-4;i<=n;++i)
for(int j=n-4;j<=n;++j)
ch[i][j]=c5[i-n+4][j-n+4];
}
if(pre[n]==7){
for(int i=n-6;i<=n;++i)
for(int j=n-6;j<=n;++j)
ch[i][j]=c7[i-n+6][j-n+6];
}
n-=pre[n];
}
n=tmp;
output();
}else puts("-1");
return 0;
}
D:
问有多少个长度为n的序列满足一下条件
且
且
解法
不妨我们弄出一个新序列,在A的基础上构造
令
好嘞,这要求为正,后面的为非负,且总和不超过n
再来考虑一下如何满足第二个条件
我们发现,当满足的时候,所有n都会满足
那考虑满足的时候b需要满足些什么
写成不等式,展开,化简,得到
其中的系数读者自行得到,非负
当然,还有另一个不等式是我们需要满足的
于是,当确定以后,的取值有个,当然负数就不能算上贡献了
于是,很容易想到,对右边的式子dp一下即可
考虑一下正确性
只要我们保证了过程中非负
且只枚举时的贡献
的取值也是会大于0的
没错
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,Mod;
#define Maxn 5005
int ans[Maxn],a[Maxn];
int main(){
scanf("%d%d",&n,&Mod);
if(n&1){
int k=(n-1)/2+1;
for(int i=0;i<=k-2;++i)a[2+i]=i;
for(int i=k-1,j=1;i>=1;--i,++j)a[k+j]=i;
}else{
int k=n/2;
for(int i=0;i<=k-2;++i)a[2+i]=i;
a[k+1]=k-1;
for(int i=k-1,j=1;i>=1;--i,++j)a[k+1+j]=i;
}
for(int i=2;i<=n;++i)a[i]++;
ans[0]=1;
for(int i=2;i<=n;++i){
for(int j=a[i];j<n;++j){
ans[j]+=ans[j-a[i]];
if(ans[j]>=Mod)ans[j]-=Mod;
}
}
int Ans=0;
for(int i=0;i<n;++i)Ans=(Ans+1ll*(n-i)*ans[i])%Mod;
printf("%d\n",Ans);
return 0;
}
E:
题意有点复杂了,不想说
解法
T=1:考虑枚举w,并且判断它可不可以。
我们从右向左加入balancer,并且动态维护一个长度为n的布尔数组B。表示当前i出发,最后会不会停止在w。一开始,只有
假设我们当前从右往左加入到了x和y
那么显然,为了让更多的出发点最后集中在w
会变成,定方向的方法很好像
如果我们每个w都进行一遍这个过程,显然不太好
bitset压位!
维护n的长度为n的bitset
其中表示当w=j时,当前时刻从i出发,会不会终止在j
初始
每次只需要
最后对去个交即可
T=2:小清新的构造
首先n=2的时候肯定不行
考虑n>2的时候,我们证明它一定有方案
同样是从右到左加入
维护一个整数数组,长度为n,其中表示i此刻出发的话,最后到达哪里
只要我们保证B每时每刻都会有两个不同的值即可
初始时显然满足
无所谓
如果在B中出现了至少两次,那么令
如果在B中出现了至少两次,同上
如果都只出现了一次,随意,然后因为n>2,所以还存在一个既不等于,也不等于的值
不同的值保证了至少存在两个
#include<iostream>
#include<cstring>
#include<cstdio>
#include<bitset>
#include<algorithm>
using namespace std;
int n,m,T;
#define Maxn 50010
int x[Maxn<<1],y[Maxn<<1];
bitset<Maxn> b[Maxn];
bool ap[Maxn];
int seq[Maxn<<1];
int to[Maxn],B[Maxn];
inline void rd(int &x){
x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
}
int main(){
rd(n);rd(m);rd(T);
for(int i=1;i<=m;++i){
rd(x[i]);rd(y[i]);
}
if(T==1){
for(int i=1;i<=n;++i)b[i][i]=1;
bitset<Maxn> res;
for(int i=m;i>=1;--i){
res=b[x[i]]|b[y[i]];
b[x[i]]=b[y[i]]=res;
}
res=b[1];
for(int i=2;i<=n;++i)res&=b[i];
int flag=-1;
for(int i=1;i<=n;++i)
if(res[i]){
flag=i;
break;
}
if(flag==-1){
puts("-1");
return 0;
}
ap[flag]=true;
for(int i=m;i>=1;--i){
if(ap[x[i]]==false&&ap[y[i]]==false)seq[i]=0;
else if(ap[x[i]]==true&&ap[y[i]]==true)seq[i]=0;
else if(ap[x[i]])seq[i]=0;
else seq[i]=1;
bool tmp=ap[x[i]]|ap[y[i]];
ap[x[i]]=ap[y[i]]=tmp;
}
for(int i=1;i<=m;++i)
if(seq[i]==0)printf("^");
else printf("v");
}else{
if(n==2){
puts("-1");
return 0;
}
for(int i=1;i<=n;++i){
B[i]=i;
to[i]=1;
}
for(int i=m;i>=1;--i){
if(B[x[i]]==B[y[i]]){
seq[i]=0;
continue;
}
if(to[B[x[i]]]>=2){
seq[i]=1;
to[B[x[i]]]--;
B[x[i]]=B[y[i]];
to[B[y[i]]]++;
}else{
seq[i]=0;
to[B[y[i]]]--;
B[y[i]]=B[x[i]];
to[B[x[i]]]++;
}
}
for(int i=1;i<=m;++i)
if(seq[i]==0)printf("^");
else printf("v");
}
return 0;
}