2025.10.21 NOIP模拟赛
(搬的长乐一中的题)
前言
分档暴力分写挂 \(10\) pts 导致排名 \(-2\)。
暴力的艺术,一题不会可以 rk7,此记。
A


Subtask1
\(f_{i,j}\) 表示前 \(i\) 个数或起来为 \(j\) 的方案数。
\(O(nt^2)\),上矩阵可以 \(O(t^3\log n)\)。
Subtask5
考虑容斥,设 \(S_k\) 表示钦定某 \(k\) 位必定不选,剩下的位可选可不选。
可以知道答案为 \(\displaystyle \sum_{k=0}^m (-1)^k S_k\)。
发现 \(2^k\bmod 3\ne 0\)。
于是将 \(t\) 的二进制下为 \(1\) 的位按模 \(3\) 的结果分为两部分,记余数为 \(i\) 的那一个集合为 \(T_i\)。
设 \(dp_{i,j,k}\) 表示当前至多选 \(i\) 个 \(1\) 位,至多选 \(j\) 个 \(2\) 位,它们的和 \(\bmod 3\) 为 \(k\) 的方案数。
注意考虑 \(i\) 与 \(j\) 时,为防止重复统计,应钦定转移顺序。
之后对于一对 \(i,j\),其对 \(S_{|T_1|+|T_2|-i-j}\) 会贡献 \(dp_{i,j,0}^n\times C_{|T_1|}^i\times C_{|T_2|}^j\)。
复杂度 \(O(\log n\log ^2 t)\)。
namespace Subtask3 {
LL dp[70][70][3],S[70],C[70][70];
void solve() {
int n1=0,n2=0;
ROF(i,61,0) if(t>>i&1) {
if((1LL<<i)%3==1) n1++;
else n2++;
}
FOR(i,0,61) C[i][0]=1;
FOR(i,1,61) FOR(j,1,i) C[i][j]=(C[i-1][j]+C[i-1][j-1])%Mo;
dp[0][0][0]=1;
FOR(i,0,n1) FOR(j,0,n2) {
if(i) FOR(k,0,2) dp[i][j][k]=(dp[i-1][j][k]+dp[i-1][j][(k+2)%3])%Mo;
if(j) FOR(k,0,2) dp[i][j][k]=(dp[i][j-1][k]+dp[i][j-1][(k+1)%3])%Mo;
}
cout<<dp[1][1][0]<<"\n";
FOR(i,0,n1) FOR(j,0,n2) (S[n1+n2-i-j]+=1LL*power(dp[i][j][0],n)*C[n1][i]%Mo*C[n2][j]%Mo)%=Mo;
LL ans=0,op=1;
FOR(i,0,n1+n2) {
ans=(ans+Mo+op*S[i])%Mo;
op=-op;
}
cout<<(ans+Mo)%Mo<<"\n";
}
}
B


答案就是所有方案中虚树的边权和的 \(2\) 倍减掉虚树直径的和再除以方案数 \(C_m^k\)。
前 \(4\) 个子任务都是白给的。
考虑转为求虚树边权和的和与虚树直径和。
前者枚举每条边,这条边能够贡献给一棵虚树当且仅当砍断这条边后,这棵虚树在两个联通块中都有点,方案是好算的。
后者直接暴力枚举直径点对,考虑钦定直径后哪些关键点满足选了之后直径不变:
假设 \(w\) 可以被选,则:
-
\(dis(u,v)<dis(u,w)\) 或者 \(dis(u,v)=dis(u,w)\and v<w\)。
-
\(dis(u,v)<dis(v,w)\) 或者 \(dis(u,v)=dis(v,w)\and u<w\)。
于是虚树的点只可能在这些点的集合中,方案数仍旧好算。
不过 \(m^3\log n\) 可能被卡,需预处理。
\(O(n^2+m^3)\)。
namespace Subtask5 {
LL len=0,dim=0;
LL Cl[N][N];
LL C(int n,int m) {
if(n<m||m<0) return 0;
return Cl[n][m];
}
void solve() {
FOR(i,0,n) Cl[i][0]=1;
FOR(i,1,n) FOR(j,1,i)
Cl[i][j]=(Cl[i-1][j-1]+Cl[i-1][j])%Mo;
LL inv=power(C(m,k),Mo-2);
FOR(i,1,n) for(int j:e[i]) {
if(dep[i]>dep[j]) continue;
int sz1=m-siz[j],sz2=siz[j];
len+=1uLL*(C(m,k)+Mo-C(sz1,k)+Mo-C(sz2,k))%Mo;len%=Mo;
}
sort(a+1,a+m+1);
FOR(i,1,m) FOR(j,i+1,m) {
int cnt=0;
FOR(z,1,m) {
if(z==i||z==j) continue;
if((la[a[z]][a[i]]==la[a[i]][a[j]]&&a[z]<a[j])||(a[z]<a[i]&&la[a[z]][a[j]]==la[a[i]][a[j]])) continue;
if(la[a[z]][a[i]]>la[a[i]][a[j]]||la[a[z]][a[j]]>la[a[i]][a[j]]) continue;
cnt++;
}
dim=(dim+1LL*C(cnt,k-2)*dis(a[i],a[j])%Mo)%Mo;
}
cout<<(len*2LL%Mo+Mo-dim)*inv%Mo<<"\n";
}
}
D


发现 \(A\) 不会往左,\(B\) 不会往右。
于是转化成 \(k/2\) 堆石子,每次可以取 \(1\sim m\) 堆,不能不取,无法取的人败。
\(NIM-K\),对于所有位 \(bit\),\(\sum [a_i>>bit\&1]\bmod (m+1)=0\),则先手必败。
证明咕咕咕~。
考虑用总的减掉先手必败方案数。
设 \(f_{i,j}\) 表正在放第 \(i\) 位,已经放完了 \(j\) 个石子,方案数。
最后剩下的石子可以插板法算贡献。
可以分析到 \(O(nk)\)。
namespace Subtask3 {
LL dp[30][N],inv[N],fac[N];
int power(int a,int b) {
int res=1;
for(;b;b>>=1) {
if(b&1) res=res*a%Mo;
a=a*a%Mo;
}
return res;
}
int C(int p,int q) {
if(p<q||q<0) return 0;
return fac[p]*inv[q]%Mo*inv[p-q]%Mo;
}
void solve() { fac[0]=1;
FOR(i,1,n) fac[i]=fac[i-1]*i%Mo;
inv[n]=power(fac[n],Mo-2);
ROF(i,n,1) inv[i-1]=inv[i]*i%Mo;
dp[0][0]=1;
FOR(i,1,14) FOR(j,0,n-k)
for(int x=0;(x<<(i-1))<=j;x+=(m+1))
(dp[i][j]+=dp[i-1][j-(x<<(i-1))]*C(k/2,x)%Mo)%=Mo;
LL ans=0;
FOR(i,0,n-k) (ans+=1LL*C(n-k/2-i,k/2)*dp[14][i]%Mo)%=Mo;
cout<<(C(n,k)-ans+Mo)%Mo<<"\n";
}
}

浙公网安备 33010602011771号