虽然CSP没过初赛没参加,但我还是想写一下题解
D1T1格雷码
按位考虑答案,第i位即为k xor [k/2]的第i位
#include<bits/stdc++.h> using namespace std; unsigned long long n,k; int main() { cin>>n>>k; while(n--) { putchar('0'+((k>>n)&1)); if((k>>n)&1)k^=(1llu<<n)-1; } }
D1T2括号树
简单树形DP,其实根本不用建边,直接O(n)循环树形DP即可
f[i]表示i到根节点路径的合法方案数
lst[i]表示上一个没匹配的位置
len[i]表示i到根的路径上匹配的括号串数
然后转移方程具体见code
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5e5+7; int n,fa[N]; ll ans,f[N],lst[N],len[N]; char c[N]; int main() { scanf("%d%s",&n,c+1); for(int i=2;i<=n;i++)scanf("%d",&fa[i]); for(int u=1,pre;u<=n;u++) { f[u]=f[pre=fa[u]],lst[u]=lst[pre]; if(c[u]=='(')lst[u]=u; else if(c[u]==')'&&lst[u])len[u]=len[fa[lst[u]]]+1,lst[u]=lst[fa[lst[u]]],f[u]+=len[u]; ans^=u*f[u]; } printf("%lld",ans); }
D1T3树上的数
什么神仙题我只会10分,先咕着
D2T1Emiya家今天的饭
感觉这题有一定难度,是有思维的DP,设f[i][j][k]表示前i行选j个节点,当前枚举列选k个节点方案数,复杂度O(mn^3),可得84分。
但这并不是我们的目标。
但我们只需要知道j,k的大小关系,即k>[j/2],即2k+n-j>n,n-j即为n行里没选的行数,然后具体转移方程可见代码
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=200,M=3000,mod=998244353; int n,m,ans=1,s[N],a[N][M],f[N][M]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++)scanf("%d",&a[i][j]),s[i]=(s[i]+a[i][j])%mod; ans=1ll*ans*(s[i]+1)%mod; } ans=(ans+mod-1)%mod; for(int i=1;i<=m;i++) { memset(f,0,sizeof f); f[0][0]=1; for(int j=1;j<=n;j++) for(int k=0;k<=2*(j-1);k++) { f[j][k]=(f[j][k]+1ll*f[j-1][k]*(s[j]-a[j][i]+mod))%mod; f[j][k+1]=(f[j][k+1]+f[j-1][k])%mod; f[j][k+2]=(f[j][k+2]+1ll*f[j-1][k]*a[j][i])%mod; } for(int j=n+1;j<=2*n;j++)ans=(ans-f[n][j]+mod)%mod; } printf("%d",ans); }
D2T2划分
先咕着
D2T3划分
咕咕咕