AT2390-[AGC016F]Games on DAG【状压dp,SG函数】
正題
題目鏈接:https://www.luogu.com.cn/problem/AT2390
解題思路
nnn個點的DAGDAGDAG,mmm條邊可有可無,111和222上有石頭。求有多少種方案使得先手必勝。
1≤n≤15,1≤m≤n(n?1)21\leq n\leq 15,1\leq m\leq \frac{n(n-1)}{2}1≤n≤15,1≤m≤2n(n?1)?
解題思路
這個復雜度比較麻煩,要設計一個比較巧妙的dpdpdp。
考慮到題目是問多少種情況SG(1)≠SG(2)SG(1)\neq SG(2)SG(1)?=SG(2),其實求SG(1)=SG(2)SG(1)=SG(2)SG(1)=SG(2)的方案會更簡單些。
設fSf_{S}fS?表示目前只考慮了生成子圖SSS時SG(1)=SG(2)SG(1)=SG(2)SG(1)=SG(2)的方案數,那么若從TTT轉移到SSS時我們可以構造一種方案使得TTT的所有點內的SGSGSG加一,然后S/TS/TS/T的所有點的SGSGSG為000。
也就相當于我們把點按照SGSGSG大小分成若干層,然后一層一層轉移進去。好了現在考慮怎么轉移fSf_SfS?,我們枚舉它的子集TTT,那么S/TS/TS/T就是它的下一層,也就是目前S/TS/TS/T內的點SG=0SG=0SG=0。
對于TTT內的每個點,我們需要連接至少一個S/TS/TS/T內的點,對于S/TS/TS/T內的點,可以隨意連接TTT內的點,枚舉一下點集統計方案就好了。
時間復雜度O(3nn)O(3^nn)O(3nn)
code
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define ll long long using namespace std; const ll N=15,P=1e9+7; ll n,m,ans,f[1<<N],c[1<<N],e[N]; vector<int>q[N]; signed main() {scanf("%lld%lld",&n,&m);for(ll i=1;i<=m;i++){ll x,y;scanf("%lld%lld",&x,&y);x--;y--;e[x]|=(1<<y);}ll MS=(1<<n),o=0;c[0]=1;for(ll i=1;i<MS;i++)c[i]=c[i-(i&-i)]*2;for(ll s=0;s<MS;s++){if((s&1)!=((s>>1)&1))continue;f[s]=1;for(ll t=(s-1)&s;t;t=(t-1)&s){ll buf=f[t];for(ll i=0;i<n;i++){if((t>>i)&1)buf=buf*(c[(s^t)&e[i]]-1)%P;if(((s^t)>>i)&1)buf=buf*c[t&e[i]]%P;}(f[s]+=buf)%=P;}}ll ans=1;while(m)m--,ans=ans*2%P;printf("%lld\n",(ans-f[MS-1]+P)%P);return 0; }總結
以上是生活随笔為你收集整理的AT2390-[AGC016F]Games on DAG【状压dp,SG函数】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 别克世纪 CENTURY 郭培联名高定系
- 下一篇: 索尼旗下《命运 2》开发商 Bungie