abc 选做
abc231g
\(\frac{1}{n^k} \sum\frac{k!}{\prod b_i!} \prod (a_i+b_i)\),其中 \(\sum b_i=k\)
构造生成函数 \(f_i=\sum \frac{a_i+j}{j!}x^j=e^x(a_i+x)\),欲求式为 \(k![x^k]\prod f_i=k![x^k] e^{nx}\prod (a_i+x)\)
预处理 \(g_i\) 为任选 \(i\) 个乘积的和,原式为 \(\frac{1}{n^k} k!\sum\limits_{i=0}^n g_{n-i} n^{k-i} \frac{1}{(k-i)!}=\sum\limits_{i=0}^n g_{n-i} \frac{k^{\underline i}}{n^i}\)
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=998244353;
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=2e3+5;
int n,k,a[N],dp[N][N],ans;
inline int ksm(int x,int y){
int res=1;
while(y){
if(y&1)res=1ll*res*x%mod;
x=1ll*x*x%mod;y>>=1;
}return res;
}
int main(){
n=read(),k=read();
for(int i=1;i<=n;i++)a[i]=read();
dp[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=i;j++)
dp[i][j]=(dp[i-1][j]+1ll*a[i]*dp[i-1][j-1])%mod;
int K=ksm(n,mod-2);
for(int i=0,k1=1,k2=1;i<=n;i++){
ans=(ans+1ll*dp[n][n-i]*k1%mod*k2)%mod;
k1=1ll*k1*K%mod;k2=1ll*k2*(k-i)%mod;
}printf("%d\n",ans);
return 0;
}
abc134f
设 \(dp_{i,j,k}\) 为到第 \(i\) 个,有 \(j\) 个未匹配,权值为 \(k\) 的方案数。分五种情况讨论转移即可。
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
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=55;
int n,K,dp[N][N][2*N*N];
inline void add(int &x,int y){x=(x+y>=mod?x+y-mod:x+y);}
int main(){
n=read(),K=read();
dp[0][0][n*n]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=i;j++)
for(int k=0;k<=2*n*n;k++){
dp[i][j][k]=dp[i-1][j][k];
if(k>=i+i)add(dp[i][j][k],1ll*(j+1)*(j+1)*dp[i-1][j+1][k-i-i]%mod);
if(j)add(dp[i][j][k],1ll*j*dp[i-1][j][k]%mod);
if(j)add(dp[i][j][k],1ll*j*dp[i-1][j][k]%mod);
if(j&&k+i+i<=2*n*n)add(dp[i][j][k],dp[i-1][j-1][k+i+i]);
}
printf("%d\n",dp[n][0][n*n+K]);
return 0;
}
abc240g
瞎扯:尝试考虑 \(2d\) 的情况,发现我也不大会,自闭了。
正解:其实是一个很经典的 trick 啊,把坐标轴倾斜,即 \((x,y)\to (x+y,x-y)\) 这时发现每一步 \(x,y\) 轴独立了,两个组合数即可。三维就枚举一维。
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e7+10;
const int mod=998244353;
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;
}
int n,X,Y,Z,fac[maxn],ifc[maxn],ans;
inline int com(int x,int y){
if(x<y||x<0||y<0)return 0;
return 1ll*fac[x]*ifc[y]%mod*ifc[x-y]%mod;
}
inline int solve1
(int N,int x){
if(x>N||(N-x)&1)return 0;
return com(N,(N+x)/2);
}
inline int solve2(int N,int x,int y){
return 1ll*solve1(N,x+y)*solve1(N,abs(x-y))%mod;
}
int main(){
n=read();X=read(),Y=read(),Z=read();
X=abs(X),Y=abs(Y),Z=abs(Z);
fac[0]=ifc[0]=ifc[1]=1;
for(int i=1;i<=n+n;i++)
fac[i]=1ll*fac[i-1]*i%mod;
for(int i=2;i<=n+n;i++)
ifc[i]=1ll*(mod-mod/i)*ifc[mod%i]%mod;
for(int i=1;i<=n+n;i++)
ifc[i]=1ll*ifc[i-1]*ifc[i]%mod;
for(int x2=0;x2+x2+X<=n;x2++)
ans=(ans+1ll*com(n,x2+x2+X)*com(x2+x2+X,x2)%mod*solve2(n-x2-x2-X,Y,Z))%mod;
printf("%d\n",ans);
return 0;
}
abc249g
给定 \(N\) 个二元组,要求第一个键值的异或和小于等于 \(K\) 的情况下,第二个键值的异或和最大。
题解:你考虑对于 \(i\neq j\),我们可以将 \((a_j,b_j)\) 变为 \((a_i\oplus a_j,b_i\oplus b_j)\),于是类似于高斯消元地,我们最终留下不超过 \(60\) 个,并且是个上三角。则我们套路地枚举相同的前缀,再每次用线性基处理 \(b\) 就好了。时间复杂度 \(O(wn+w^3)\)
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e3+5;
#define btst bitset<N>
const int maxn=2e5+10;
const int mod=1e9+7;
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;
}
#define ll long long
const int all=(1<<30)-1;
ll t[N];
inline int cmp(ll x,ll y){return x>y;}
int n,K,a[N],b[N],ans=-1,cur,l[50],flg;
inline void add(int x){
for(int i=30;~i;--i)if(x>>i&1){
if(l[i])x^=l[i];
else{l[i]=x;return;}
}flg=1;
}
inline void solve(int bt){
// printf("solve bt=%d\n",bt);
memset(l,0,sizeof(l));
for(int i=1;i<=n;i++)
if((a[i]>>bt)==0)add(b[i]);
int res=cur;
for(int i=30;~i;--i)
if(l[i]&&((res>>i&1)==0))res^=l[i];
ans=max(ans,res);
}
signed main(){
n=read(),K=read()+1;
for(int i=1;i<=n;i++)
a[i]=read(),b[i]=read();
for(int i=1;i<=n;i++)add(a[i]);
int Mn=K;
for(int i=0;i<=30;i++)
if(l[i]){Mn=l[i];break;}
if(flg)Mn=0;
if(Mn>=K)return puts("-1")&0;
for(int i=1;i<=n;i++)
t[i]=(b[i]|((ll)a[i]<<30));
for(int i=60;~i;--i){
sort(t+1,t+1+n,cmp);
int p=0;
for(int j=1;j<=n;j++)
if((t[j]>>i&1)&&((t[j]>>i+1)==0)){p=j;break;}
if(!p)continue;
for(int j=p+1;j<=n;j++)
if(t[j]>>i&1)t[j]^=t[p];
}
// for(int i=1;i<=n;i++)
// printf("%lld %lld\n",t[i]>>30,t[i]&all);puts("");
int lim=0;
for(int i=1;i<=n;i++)
if(t[i])lim=i;n=lim;
for(int i=1;i<=n;i++)
a[i]=t[i]>>30,b[i]=t[i]&all;
int now=0;
for(int i=30;~i;--i){
int p=0;
for(int j=1;j<=n;j++)
if((a[j]>>i&1)&&((a[j]>>i+1)==0)){p=j;break;}
if((K>>i&1)==0){
if(now>>i&1){
if(!p)break;
now^=a[p],cur^=b[p];
}else continue;
}else{
if(now>>i&1){
if(!p)continue;
cur^=b[p];solve(i);cur^=b[p];
}else{
solve(i);if(!p)break;
now^=a[p],cur^=b[p];
}
}
//if(!p)break;now^=a[p],cur^=b[p],flg1=1;
}printf("%lld\n",ans);
return 0;
}