AB
签到
C
大力DP,f[i][j]表示走到当前位置的方案数,但问题是无法考虑没走过路径的未填位置。不过很好解决,向右走的时候实际方案=原方案数*3^(走过的列下侧的未填位置数),向下走的时候实际方案=原方案数*3^(走过的行右侧的未填位置数),这样可以处理掉所有的未填位置。
#include<bits/stdc++.h> using namespace std; const int N=5005,mod=998244353; int n,m,k,pw[N],a[N][N],f[N][N],s[N][N],t[N][N]; int main() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)a[i][j]=-1; pw[0]=1;for(int i=1;i<=5000;i++)pw[i]=3ll*pw[i-1]%mod; for(int i=1,x,y;i<=k;i++) { char c;scanf("%d%d %c",&x,&y,&c); if(c=='X')a[x][y]=0; else if(c=='R')a[x][y]=1; else a[x][y]=2; } for(int j=1;j<=m;j++) { for(int i=n;i;i--)s[i][j]=s[i+1][j]+(a[i][j]==-1); } for(int i=1;i<=n;i++) { for(int j=m;j;j--)t[i][j]=t[i][j+1]+(a[i][j]==-1); } f[1][1]=1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(j>1) { if(!a[i][j-1]||a[i][j-1]==1)f[i][j]=(f[i][j]+1ll*f[i][j-1]*pw[s[i+1][j-1]])%mod; else if(a[i][j-1]==-1)f[i][j]=(f[i][j]+2ll*f[i][j-1]*pw[s[i+1][j-1]])%mod; } if(i>1) { if(!a[i-1][j]||a[i-1][j]==2)f[i][j]=(f[i][j]+1ll*f[i-1][j]*pw[t[i-1][j+1]])%mod; else if(a[i-1][j]==-1)f[i][j]=(f[i][j]+2ll*f[i-1][j]*pw[t[i-1][j+1]])%mod; } } if(a[n][m]==-1)f[n][m]=3ll*f[n][m]%mod; printf("%d",f[n][m]); }
D
构造能力堪忧于是成功垫底……
很容易发现答案是2^n-1,但就是不会构造……
发现可以将2^(n-1)个人时的答案进行如下复制,假设一个答案是A,则可以复制成AA,AB,其中B与A完全不同,再加上A…AB…B就可达到目的
#include<bits/stdc++.h> using namespace std; int n; int main() { scanf("%d",&n); printf("%d ",(1<<n)-1); vector<string>a; for(int i=1;i<=n;i++) { vector<string>vec; string x=""; for(int j=1;j<=(1<<i-1);j++)x+='A'; for(int j=1;j<=(1<<i-1);j++)x+='B'; vec.push_back(x); for(int j=0;j<a.size();j++) { vec.push_back(a[j]+a[j]); string s=a[j]; for(int k=0;k<s.size();k++)s[k]=s[k]=='A'?'B':'A'; vec.push_back(a[j]+s); } a=vec; } for(int i=0;i<a.size();i++)cout<<a[i]<<endl; }
E
考完发现实际上就是DP,f[i][j][k]表示在区间[i,j],取了k个区间外的数的最大值,也是直接DP就行了
#include<bits/stdc++.h> using namespace std; const int N=405; int n,a[N],f[N][N][N]; int dp(int l,int r,int m) { int&ret=f[l][r][m]; if(ret)return ret; int t=0; if(l>0||r<=n) { if(m<n-(r-l-1)) { if(a[l]<a[r])t=max(t,dp(l,r+1,m+1)); else t=max(t,dp(l-1,r,m+1)); } if(m>=1&&l>=1)t=max(t,a[l]+dp(l-1,r,m-1)); if(m>=1&&r<=n)t=max(t,a[r]+dp(l,r+1,m-1)); } ret=t; return ret; } int main() { cin>>n; for(int i=1;i<=n;i++)cin>>a[i]; a[0]=a[n+1]=-1; for(int i=0;i<=n;i++)cout<<dp(i,i+1,1)<<endl; }
小号打的 rank=426 performance=1931 rating+=149