1. 程式人生 > >jzoj5765 【省選模擬8.5】相互再歸的鵝媽媽 (集合劃分,斯特林反演)

jzoj5765 【省選模擬8.5】相互再歸的鵝媽媽 (集合劃分,斯特林反演)

這裡寫圖片描述

mk<=5e6m<=5e4

解法

先考慮可以有相同怎麼做:
列舉一個第一個脫離限制的位置,然後用一個脫離限制的數來安排使得異或和為0,其他數可以任意取(要分是否脫離限制確定方案數)。這樣可以計算出g(n)表示n個可以相同的數,異或和為0的答案。

斯特林反演式子:
[n=1]=mA(ai1)!(1)ai1

證明非常簡單,右側是圓周排列加上一個正負1的係數
等式右邊也就是

ks(n,k)(1)nk
,其中k是所劃分的集合個數。
不難得出s(n)(1)nk的生成函式就是x(x1)(x2)...(xn+1)=xn
令x=1,那麼等式右側就是1n=s(n,0)+,即=[n=1]
我們要求的就是滿足[ai=1]根據這個反演一波即可。
#include <cstdio>
#include <iostream>
#include <cstring>
#define lowbit(x) ((x) & -(x))
using namespace std; typedef long long ll; const ll mo = 1e9 + 7; ll n, m, k, len; char s[50100]; ll a[5000100],suf[5000100],mi[5000100]; ll f[8][2][2],g[8],ans,jc[8],mir[8]; ll q[8],size[8]; void dfs(ll x,ll c) { if (x > n) { memset(size,0,sizeof size); for (ll i = 1; i <= n; i++) size[q[i]
]++; ll eve = 0, xs = 1; for (ll i = 1; i <= c; i++) { if (size[i] % 2 == 0) eve++; xs = xs * jc[size[i] - 1] % mo * ((size[i]-1)%2==0?1:-1) % mo; } ll odd = c - eve; (ans += xs * g[odd] % mo * mir[eve]) %= mo; return; } q[x] = c + 1; dfs(x + 1, c + 1); for (ll i = 1; i <= c; i++) { q[x] = i; dfs(x + 1, c); } } ll ksm(ll x,ll y) { ll ret = 1; for (; y; y>>=1) { if (y & 1) ret = ret * x % mo; x = x * x % mo; } return ret; } int main() { freopen("mothergoose.in","r",stdin); freopen("mothergoose.out","w",stdout); cin>>n>>k; jc[0] = 1; for (ll i = 1; i <= n; i++) jc[i] = jc[i - 1] * i; scanf("%s",s + 1); m = strlen(s + 1); for (ll i = 1; i <= k; i++) for (ll j = 1; j <= m; j++) { a[++len] = s[j] - '0'; } ll w = 1; mi[len+1] = 1; for (ll i = len; i; i--, w = w * 2 % mo) { suf[i] = (suf[i+1] + w * a[i]) % mo; mi[i] = w * 2 % mo; } mir[0] = 1; for (ll i = 1; i <= n; i++) mir[i] = mir[i - 1] * suf[1] % mo; ll hasone = 0; for (ll i = 1; i <= len; i++) if (a[i] == 1) { memset(f,0,sizeof f); f[0][0][0] = 1; for (ll j = 1; j <= n; j++) { for (ll z = 0; z < 2; z++) //odd or even for (ll e = 0; e < 2; e++) { //has or not (f[j][z^1][e] += f[j-1][z][e] * suf[i+1]) %=mo; (f[j][z][1] += f[j-1][z][e] * (e == 1 ? mi[i+1] : 1)) %= mo; } if (j%2==0 || !hasone) { (g[j] += f[j][0][1]) %= mo; } } hasone = 1; } g[0] = 1; dfs(1,0); ans = (ans + mo) % mo; cout<<ans * ksm(jc[n], mo - 2) % mo<<endl; }