ARC162 简要题解
ABC 没做。
D. Smallest Vertices
对每个点算贡献。首先生成树的数量为
那么对于一个点
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
const int mod=998244353;
#define inf 1e9
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=505;
int n,m,fac[N],inv[N],ifc[N],ans,d[N],dp[N][N],kk=1;
inline void add(int &x,int y){x=(x+y>=mod?x+y-mod:x+y);}
int main(){
n=read();fac[0]=ifc[0]=inv[1]=1;
for(int i=1;i<=n;i++)fac[i]=1ll*i*fac[i-1]%mod;
for(int i=2;i<=n;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=n;i++)ifc[i]=1ll*ifc[i-1]*inv[i]%mod;
for(int i=1;i<=n;i++)d[i]=read(),kk=1ll*kk*ifc[d[i]]%mod;
kk=1ll*kk*d[1]%mod;ans=1ll*kk*fac[n-2]%mod;dp[0][0]=1;
for(int i=n;i>=2;i--){
if(!d[i])ans=(ans+1ll*kk*fac[n-2])%mod;
else for(int j=2;j<=n-i+1;j++)if(j-d[i]>0)
ans=(ans+1ll*dp[j-1][j-1-d[i]]*kk%mod*fac[j-2]%mod*fac[n-j-1]%mod*d[i])%mod;
for(int j=n-i+1;j>=0;j--)
for(int k=n-d[i];k>=0;k--)
add(dp[j+1][k+d[i]],dp[j][k]);
}printf("%d\n",ans);
return 0;
}
E. Strange Constraints
挺有意思的题,反正比 F 优美不少。
首先
这时你写出来发现算重了,是因为如果出现次数相同则两者完全等价,需要除以阶乘。但是关注到出现次数为
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
const int mod=998244353;
#define inf 1e9
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=505;
int n,m,a[N],c[N],dp[2][N][N],S[N][N],C[N][N],ans,inv[N],ifc[N],fac[N];
inline void add(int &x,int y){x=(x+y>=mod?x+y-mod:x+y);}
int main(){
n=read();inv[1]=fac[0]=ifc[0]=1;
for(int i=2;i<=n;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mod;
for(int i=1;i<=n;i++)ifc[i]=1ll*ifc[i-1]*inv[i]%mod;
for(int i=0;i<=n;i++){
C[i][0]=1;
for(int j=1;j<=i;j++)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}for(int i=1;i<=n;i++)
a[i]=read(),c[a[i]]++;
sort(a+1,a+1+n);
for(int i=n;i>=1;i--)c[i]+=c[i+1];
dp[(n+1)&1][0][0]=1;
for(int i=n;i>=1;i--){
int o=(i&1);
memset(dp[o],0,sizeof(dp[o]));
int Mx=n/i;
for(int j=0;j<=Mx;j++)
for(int k=0;k<=n;k++){
int v=dp[o^1][j][k],kk=1;
add(dp[o][j][k],v);
for(int p=1;k+p*i<=min(n,c[i])&&j+p<=min(n,1+c[i]);p++){
kk=1ll*kk*max(0,c[i]-j-p+1)%mod*C[c[i]-k-(p-1)*i][i]%mod;
add(dp[o][j+p][k+p*i],1ll*kk*v%mod*ifc[p]%mod);
}
}
}for(int i=1;i<=n;i++)ans=(ans+dp[1][i][n])%mod;
printf("%d\n",ans);
return 0;
}
F. Montage
弱智题,不知道为什么放 F,不知道为什么评大红。
首先由于我的个人问题,不妨反转一下条件的符号,其实也就是把矩阵反过来看。
我们注意到
1
11
1111
1111
11
1
图不是很典型,大概意会一下就能体会到。
我们 dp 上沿的轮廓线,可以往右走或者往下走,往下走时可以继承一个不大于上面的长度。具体细节不难编。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
const int mod=998244353;
#define inf 1e9
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
inline void add(int &x,int y){x=(x+y>=mod?x+y-mod:x+y);}
inline int Add(int x){return x>=mod?x-mod:x;}
const int N=405;
int n,m,f[N][N][N],g[N][N][N],ans,S[N];
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)f[i][0][0]=1;
for(int j=1;j<=m;j++){
for(int k=0;k<=m;k++)S[k]=0;
int tot=0;
for(int i=1;i<=n;i++){
int sum=0;add(f[i][j][1],tot);
for(int k=m;k>=0;k--){
if(k){
add(f[i][j][k],Add(f[i][j-1][k-1]+g[i][j-1][k-1]));
add(f[i][j][k],S[k]);
}g[i][j][k]=Add(f[i][j-1][k]+g[i][j-1][k]);
add(sum,f[i][j][k]);add(S[k],sum);
if(k)add(tot,g[i][j][k]);
}add(ans,sum);
}
}printf("%d\n",ans+1);
return 0;
}
深深地感到自己的弱小。