Codeforces Round #663 (Div. 2)
A. Suborrays
题解
构造一个序列使得任意区间按位或的答案大于等于区间长度,打个表发现好像啥都行,于是就瞎输出了
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
inline int read()
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
int T,n;
int main()
{
T=read();
while(T--)
{
n=read();
for(int i=1;i<n;i++)printf("%d ",i);
printf("%d\n",n);
}
return 0;
}
B. Fix You
题解
一开始读错题了以为LRUD都有,结果发现只有RD,于是就只需要判下面是不是都是R,右边是不是都是D就好了
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
inline int read()
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
int n,m,a[110][110];
char pic[110][110];
bool vis[110][110];
bool legal(int x,int y)
{
return (x>=0 && x<n) && (y>=0 && y<m);
}
queue<PII> Q;
int main()
{
for(int T=read();T;T--)
{
n=read();m=read();
for(int i=0;i<n;i++)for(int j=0;j<m;j++)vis[i][j]=a[i][j]=0;
for(int i=0;i<n;i++)scanf("%s",pic[i]);
int cnt=0;
for(int i=0;i<m-1;i++)if(pic[n-1][i]!='R')cnt++;
for(int i=0;i<n-1;i++)if(pic[i][m-1]!='D')cnt++;
printf("%d\n",cnt);
}
return 0;
}
C. Cyclic Permutations
题解
题目花里胡哨的说了一坨,反正推了一下发现满足题意的就是这个序列需要有一个谷底,那么我们反其道行之,求不存在谷底的排列有多少就行,设峰值\(n\) 在\(i\) 位置,那么我们剩下\(n-1\)个数就已经按顺序拍好了,有\(C_{n-1}^{i-1}\) 种方案,最后用\(n!\) 减去\(\sum_{i=0}^{n-1} C_{n-1}^i\) 即可,(其实那玩意就是\(2_{n-1}\) 没有发现)
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
inline int read()
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int MOD=1000000007,maxn=1000010;
int n;
LL fac=1,inv[maxn],C[maxn],ans;
int main()
{
n=read();
for(int i=1;i<=n;i++)fac=(fac*i)%MOD;
inv[1]=1;
for(int i=2;i<=n;i++)inv[i]=((MOD-MOD/i)*inv[MOD%i])%MOD;
C[0]=1;
for(int i=1;i<=n-1;i++)C[i]=(C[i-1]*LL(n-i))%MOD*inv[i]%MOD;
for(int i=1;i<=n;i++)ans=(ans+C[i-1])%MOD;
printf("%lld\n",((fac-ans)%MOD+MOD)%MOD);
return 0;
}
D. 505
题解
题目大意是给你一个01矩阵,问最少修改多少个数,使得这个矩阵的所有偶数边长的子正方形矩阵里面都有奇数个1。
很容易发现,当\(n>3\)的时候,存在一个\(4*4\) 的矩阵,里面还包含着4个\(2*2\) 的矩阵,这个肯定是矛盾的,所以就只讨论\(n<4\) 的情况。
当\(n=1\) 的时候答案是0, 当\(n=2或者n=3\) 的时候就状压DP设\(dp[i][s]\) 表示当前在第\(i\) 列,第\(i\) 列的01摆法为S就可以了,复杂度是\(O(4*4*n/2)或者O(8*8*n/6)\)
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
inline int read()
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int maxn=1000010,inf=maxn;
int n,m,a[4][maxn],dp[maxn][2][2],DP[maxn][8];
char s[4][maxn];
int main()
{
n=read();m=read();
if(n>=4)return puts("-1"),0;
if(n==1)return puts("0"),0;
for(int i=0;i<n;i++)scanf("%s",s[i]);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)a[i][j]=s[i][j]-'0';
if(n==2)
{
for(int i=0;i<m;i++)dp[i][0][0]=dp[i][0][1]=dp[i][1][0]=dp[i][1][1]=inf;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
if(a[0][0]==i && a[1][0]==j)dp[0][i][j]=0;
else dp[0][i][j]=1;
for(int i=1;i<m;i++)
{
for(int jj=0;jj<2;jj++)
for(int kk=0;kk<2;kk++)
{
int cnt=2;
if(a[0][i]==jj)cnt--;
if(a[1][i]==kk)cnt--;
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
if((j+k+jj+kk)%2)dp[i][jj][kk]=min(dp[i][jj][kk],dp[i-1][j][k]+cnt);
}
}
int ans=maxn;
for(int i=0;i<2;i++)for(int j=0;j<2;j++)ans=min(ans,dp[m-1][i][j]);
printf("%d\n",ans);
return 0;
}
if(n==3)
{
for(int i=0;i<m;i++)for(int j=0;j<8;j++)DP[i][j]=inf;
for(int i=0;i<8;i++)
{
int S1=i&1,S2=(i>>1)&1,S3=(i>>2)&1;
int cnt=3;
if(a[0][0]==S1)cnt--;
if(a[1][0]==S2)cnt--;
if(a[2][0]==S3)cnt--;
DP[0][i]=cnt;
}
for(int i=1;i<m;i++)
{
for(int S=0;S<8;S++)
{
int S1=S&1,S2=(S>>1)&1,S3=(S>>2)&1;
// printf("%d %d%d%d\n",S,S1,S2,S3);
int cnt=3;
if(a[0][i]==S1)cnt--;
if(a[1][i]==S2)cnt--;
if(a[2][i]==S3)cnt--;
for(int s=0;s<8;s++)
{
int s1=s&1,s2=(s>>1)&1,s3=(s>>2)&1;
// if(i==1 && S==6)printf("%d %d %d %d %d %d\n",s1,s2,s3,S1,S2,S3);
if((S1+s1+S2+s2)%2 && (S2+s2+S3+s3)%2)DP[i][S]=min(DP[i][S],DP[i-1][s]+cnt);
}
// printf("%d %d %d\n",i,S,DP[i][S]);
}
}
// for(int i=0;i<m;i++)for(int S=0;S<8;S++)printf("%d %d %d\n",i,S,DP[i][S]);
int ans=maxn;
for(int i=0;i<8;i++)ans=min(ans,DP[m-1][i]);
printf("%d\n",ans);
}
return 0;
}
E. Pairs of Pairs
题解
又是一道很诡异的题,题目大意是给你一个无向图,你要不在图中找到一个长度大于等于\(\lceil \frac{n}{2} \rceil\) 的简单路径,要不就找若干个二元组(其中这些二元组的元素不能重复,至少要多于等于\(\lceil \frac{n}{2} \rceil\) ),使得任意两个二元组组成的子图,至多有两条边。
直接看了题解,题解是随便找一点开始求他的dfs树,如果dfs树中有深度大于等于\(\lceil \frac{n}{2} \rceil\) 的点,就直接输出即可,否则就找所有深度相同的点,两两配对,一定能保证配出\(\lceil \frac{n}{4} \rceil\) 对。怎么证明呢?
先证这任意两个二元组组成的子图吧,根据dfs树的性质,所有非树边一定是祖先连往子孙,不可能存在子树之间的连边 ,深度相同的点显然是属于两个子树,所以保证两个二元组\((a,b),(c,d)\) 其中\(deep[a]=deep[b],deep[c]=deep[d]\) 令\(deep[a]<deep[c]\),a和b 不可能连边,c和d不可能连边,那两条边只可能是a和c,b和d为父子关系的时候才可以算上。
再证一定大于\(\lceil \frac{n}{4} \rceil\) 对,因为不存在深度大于\(\lceil \frac{n}{2} \rceil\) 了,所以最大深度不过\(\lceil \frac{n}{2} \rceil\) ,每一个深度只有当有0个或者1个节点的时候才会放弃这个深度,根据抽屉原理一定能选出\(\lceil \frac{n}{4} \rceil\) 对满足。
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
inline int read()
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int maxn=500010,maxm=1000010;
int n,m,a,b,deep[maxn],pa[maxn],max_deep;
vector<int> G[maxn],deep_pair[maxn];
bool path,vis[maxn];
void dfs(int now,int fa)
{
vis[now]=1;
pa[now]=fa;
if(path)return;
deep_pair[deep[now]].push_back(now);
max_deep=max(max_deep,deep[now]);
if(deep[now]>=(n+1)/2)
{
int tmp=now;
printf("PATH\n%d\n",deep[now]);
while(tmp!=1)printf("%d ",tmp),tmp=pa[tmp];
puts("1");
path=1;
return;
}
for(int v:G[now])
if(v!=fa && !vis[v])
deep[v]=deep[now]+1,dfs(v,now);
}
int main()
{
for(int T=read();T;T--)
{
n=read();m=read();
max_deep=path=0;
for(int i=1;i<=n;i++)G[i].clear(),vis[i]=0;
for(int i=1;i<=m;i++)a=read(),b=read(),G[a].push_back(b),G[b].push_back(a);
deep[1]=1;
dfs(1,0);
if(!path)
{
int cnt=0;
for(int i=2;i<=max_deep;i++)cnt+=deep_pair[i].size()/2;
printf("PAIRING\n%d\n",cnt);
// for(int i=1;i<=max_deep;i++)
// {
// printf("deep %d:",i);
// for(int j=0;j<deep_pair[i].size();j++)printf("%d ",deep_pair[i][j]);
// puts("");
// }
for(int i=2;i<=max_deep;i++)
{
for(int j=0;j+1<deep_pair[i].size();j+=2)printf("%d %d\n",deep_pair[i][j],deep_pair[i][j+1]);
}
}
for(int i=1;i<=max_deep;i++)deep_pair[i].clear();
}
return 0;
}