20200603
- rk 10/10, 60+0+3=63
- max: 100+50+35+185
石子游戏
相当于选出最少的数使得异或和等于所有数的异或和。显然一定有解,且解的大小 \(<\log a\)(根据线性基理论)。因此从小到大枚举答案,用 fwt 做异或卷积。只需要判断是否非 \(0\) 所以可以把方案数取模,zsy 甚至写了四模数
注意只需要一个位置的点值,手动 ifwt 可以做到 \(O(n\log a)\)
code
const int N = 1<<19;
int n,s;
LL a[N],f[N];
void fwt(LL a[]) {
for(int i = 1; i < N; i <<= 1) for(int j = 0; j < N; j += i<<1) Rep(k,0,i) {
LL x = a[j+k], y = a[j+k+i];
a[j+k] = Mod(x+y), a[j+k+i] = Mod(x-y+mod);
}
}
void ifwt(LL a[]) {
for(int i = 1; i < N; i <<= 1) for(int j = 0; j < N; j += i<<1) Rep(k,0,i) {
LL x = a[j+k], y = a[j+k+i];
a[j+k] = (x+y) * iv2 %mod, a[j+k+i] = (x-y+mod) * iv2 %mod;
}
}
signed main() {
#ifdef FS
freopen("a.in","r",stdin);// freopen("a.out","w",stdout);
#endif
io>>n; For(i,1,n, x) io>>x, s ^= x, a[x] = 1;
if( !s ) io<<n, exit(0);
fwt(a), f[0] = 1, fwt(f);
for(int i = 1; ; ++i) {
Rep(j,0,N) (f[j] *= a[j]) %=mod;
LL cnt=0; Rep(j,0,N) ckadd(cnt, __builtin_parity(s&j)?mod-f[j]:f[j]);
if( cnt ) io<<n-i, exit(0);
}
}
函数
可以 min25 但过不了,考虑 PN 筛。
构造 \(g=id_{k}\),归纳得到 \(h(p^{e})=p^{k}-p^{2k}\)
卡常的话可以在 dfs PN 时先只记录每个自然数幂和的系数,这样只需要算一遍自然数幂和
code
const int N = 3.2e6;
int m,sq,pri;
LL n,p[N],hp[N];
struct {
LL ivf[25],y[25],pre[25],suf[25];
void init() {
ivf[0] = ivf[1] = pre[0] = suf[23] = 1;
For(i,2,22) ivf[i] = (mod-mod/i)*ivf[mod%i]%mod;
For(i,2,22) (ivf[i] *= ivf[i-1]) %=mod;
For(i,1,22) y[i] = Mod(y[i-1]+Pow(i,m));
For(i,1,22) (y[i] *= (22-i&1?mod-1:1)*ivf[i-1]%mod*ivf[22-i]%mod) %=mod;
}
LL operator () (LL x) {
x %=mod;
For(i,1,22) pre[i] = pre[i-1] * Mod(x-i+mod) %mod;
rFor(i,22,1) suf[i] = suf[i+1] * Mod(x-i+mod) %mod;
LL res=0; For(i,1,22) ckadd(res,y[i] * pre[i-1]%mod*suf[i+1]%mod);
return res;
}
} L;
void sieve(int n) {
static bitset<N> vis;
For(i,2,n) {
if( !vis[i] ) p[++pri] = i;
for(int j = 1; j <= pri && i*p[j] <= n; ++j)
{ vis[i*p[j]] = 1; if( !(i % p[j]) ) break; }
} p[pri+1] = n+1;
For(i,1,pri) hp[i] = Mod(Pow(p[i],m) - Pow(p[i],2*m) +mod);
}
LL dfs(int i,LL x,LL h) {
LL y = n/x, res = h * L(y) %mod;
for(; p[i]*p[i] <= y; ++i) for(LL pe = p[i]*p[i]; pe <= y; pe *= p[i])
ckadd(res,dfs(i+1,x*pe,h*hp[i]%mod));
return res;
}
signed main() {
#ifdef FS
freopen("a.in","r",stdin);// freopen("a.out","w",stdout);
#endif
io>>n>>m, sq = sqrt(n), sieve(sq), L.init();
io<<dfs(1,1,1);
return 0;
}
画
缠了 zsy 和 yzf 一晚上才明白,感谢两位大佬,我的计数确实太差了
考虑 \(m=0\)。枚举 \(i\) 表示 \(n\) 个数前 \(i\) 位顶上界(且异或和等于 \(C\) 的前 \(i\) 位)。选出一个数使其在当前为 \(<\) 上界,那么其他数低位可以随便填,用该数来控制异或和。可以 DP:设 \(f[j,0/1,0/1]\) 表示前 \(j\) 个数,该位异或和为 \(0/1\),是否有数 \(<\) 上界
注意特判 \(\oplus limit_{i}=C\)
\(m>0\) 的情况可以考虑容斥,钦定边集 \(E\) 不合法(\((u,v)\in E,col_{u}=col_{v}\)),容斥系数为 \((-1)^{|E|}\)。\(E\) 会把图分成若干连通块,类似 ABC236Ex 那样优化,一个连通块的容斥系数之和可以由任意连边的 \(-\) 不连通的得到。设 \(f[s,t]\) 表示已经加入的集合 \(s\) 中的点,奇数大小连通块的最小 \(limit\) 取值点集合为 \(t\) 的方案数,枚举补集转移即可
强制新加入的连通块包含补集的最小值那么复杂度为 \(\sum_{i=0}^{n}3^{i}2^{n-i}=O(3^{n})\)
code
const int N = 15;
int n,m,U,mn[1<<N];
LL c,a[N],f[1<<N];
bitset<1<<N> vis;
gp_hash_table<int,LL> g[1<<N];
LL dp(int s) {
static LL b[N],f[N+1][2][2];
int m = 0; LL ans = 0;
Rep(i,0,n) if( s>>i & 1 ) b[m++] = a[i];
rFor(i,59,0) {
memset(f,0,sizeof f), f[0][0][0] = 1;
Rep(j,0,m) {
LL low = ((b[j]&(1ll<<i)-1) + 1) %mod;
For(k,0,1) For(l,0,1) if( f[j][k][l] ) {
if( b[j]>>i & 1 ) {
if( k ) (f[j+1][k][l] += (1ll<<i) %mod * f[j][k][l]) %=mod;
else ckadd(f[j+1][1][l],f[j][k][l]);
(f[j+1][k][!l] += f[j][k][l] * low) %=mod;
} else (f[j+1][k][l] += f[j][k][l] * low) %=mod;
}
}
ckadd(ans,f[m][1][c>>i&1]);
bool val=0; Rep(j,0,m) val ^= b[j]>>i&1;
if( val != (c>>i & 1) ) return ans;
}
return Add(ans,1);
}
signed main() {
#ifdef FS
freopen("a.in","r",stdin);// freopen("a.out","w",stdout);
#endif
io>>n>>m>>c, U = (1<<n)-1; Rep(i,0,n) io>>a[i];
For(i,1,m, u,v) {
io>>u>>v, --u,--v;
For(s,0,U) if( (s>>u & 1) && (s>>v & 1) ) vis[s] = 1;
}
For(s,1,U) {
LL x = LLONG_MAX;
Rep(i,0,n) if( (s>>i & 1) && ckmin(x,a[i]) ) mn[s] = i;
}
For(s,1,U) {
f[s] = !vis[s];
for(int t = s-1&s; t; t = t-1&s)
if( (t & (s&-s)) && !vis[s^t] ) ckdel(f[s],f[t]);
}
g[0][0] = 1;
For(s,0,U) for(auto &gi : g[s]) {
int t; LL dp; tie(t,dp) = gi;
for(int i = U^s, j = i; j; j = j-1&i) if( j>>mn[i] & 1 ) {
if( __builtin_parity(j) )
(g[s|j][t|1<<mn[j]] += f[j] * dp) %=mod;
else
(g[s|j][t] += (a[mn[j]]+1) %mod * f[j] %mod * dp) %=mod;
}
}
LL ans=0; for(auto &i : g[U]) (ans += i.se * dp(i.fi)) %=mod;
io<<ans;
return 0;
}