UR#6 懒癌
超級(jí)結(jié)論題。。。
首先建出原圖的補(bǔ)圖,再考慮縮點(diǎn)。
縮完點(diǎn)后是一個(gè)有向無(wú)環(huán)圖。
這個(gè)圖的每個(gè)點(diǎn)代表一個(gè)強(qiáng)聯(lián)通分量。
考慮一個(gè)大小大于\(1\)的強(qiáng)聯(lián)通分量中的一個(gè)點(diǎn)\(i\),那么\(i\)永遠(yuǎn)不可能開槍。
因?yàn)?span id="ozvdkddzhkzd" class="math inline">\(i\)開槍需要假設(shè)自己的狗沒病,然后枚舉自己看不到的狗的狀態(tài),然而由于有他的轉(zhuǎn)移依賴的狀態(tài) 依賴他,那么就會(huì)循環(huán)轉(zhuǎn)移。
導(dǎo)致他一直到inf都不會(huì)開槍。
那么任何可以到達(dá)大于1的強(qiáng)聯(lián)通分量的強(qiáng)聯(lián)通分量都廢了(包括本身),因?yàn)樗麄冎兴悬c(diǎn)都只能不是病狗。
現(xiàn)在每個(gè)強(qiáng)聯(lián)通分量都是單點(diǎn)強(qiáng)聯(lián)通分量。
考慮一個(gè)狀態(tài),每個(gè)病狗的主人都非常聰明但也非常謹(jǐn)慎,它從他的狗沒病,并且他不知道的狗狀態(tài)隨便的狀態(tài) 中 開槍時(shí)間最大 的一種 轉(zhuǎn)移過來(lái)。
然后所有主人的答案取\(min\)。
這樣一次最多在 可到達(dá)點(diǎn)集 中去掉一個(gè)點(diǎn),且肯定可以去掉一個(gè)點(diǎn),因?yàn)橥負(fù)湫蜃钚〉狞c(diǎn)肯定去掉后再也不能被染黑了。
那么可以容易得出,狀態(tài)的貢獻(xiàn)就是它可以到的點(diǎn)集大小。再計(jì)算點(diǎn)的貢獻(xiàn)。
考慮只有凸集上的點(diǎn)才能貢獻(xiàn)答案(因?yàn)槟闳in的時(shí)候只能選凸集上的點(diǎn)),第二問也可以用點(diǎn)的貢獻(xiàn)做。
#include <bits/stdc++.h>using namespace std; const int N=3010; typedef long long ll; int dfn[N],low[N],clk; int isc[N],sz[N],nscc; stack<int> st; vector<int> e[N],g[N]; void Tajan(int x){//cerr<<"Tajan"<<x<<endl;dfn[x]=low[x]=++clk;st.push(x);for (auto i:e[x]){if (!dfn[i]) Tajan(i);if (!isc[i]) low[x]=min(low[x],low[i]);}if (dfn[x]==low[x]){++nscc;while (1){int u=st.top(); st.pop();isc[u]=nscc;++sz[nscc];//cerr<<"pop"<<nscc<<" "<<u<<endl;if (u==x) break;}} } bitset<N> b[N];const int M=998244353;int add(int x,int y){return (x+=y)>=M?x-M:x; } int sub(int x,int y){return (x-=y)<0?x+M:x; } int fp(int x,int y){int ret=1;for (; y; y>>=1,x=(ll)x*x%M) if (y&1) ret=(ll)ret*x%M;return ret; } char s[N]; int n; int fc[N]; vector<int> ups[N]; int f[N]; int main(){scanf("%d",&n);for (int i=1; i<=n; ++i){scanf("%s",s+1);for (int j=1; j<=n; ++j)if (j!=i&&s[j]=='0'){//cerr<<i<<" "<<j<<endl;e[i].push_back(j);}}for (int i=1; i<=n; ++i){//cerr<<"????"<<i<<endl;if (!dfn[i]) Tajan(i);}//cerr<<nscc<<endl;for (int i=1; i<=n; ++i){for (auto j:e[i]){int x=isc[i];int y=isc[j];ups[y].push_back(x);if (sz[x]>1||sz[y]>1) continue;g[x].push_back(y);}}queue<int> q;for (int i=1; i<=nscc; ++i)if (sz[i]>1) q.push(i),f[i]=0; else f[i]=1000000;while (!q.empty()){int x=q.front(); q.pop();for (auto j:ups[x])if (f[j]==1000000){f[j]=f[x]+1;q.push(j);}}int tot=0,ans1=0,ans2=0;for (int i=1; i<=nscc; ++i) tot+=(sz[i]==1&&f[i]==1000000);for (int i=1; i<=n; ++i) fc[isc[i]]=i;for (int i=nscc; i>=1; --i)if (sz[i]==1&&f[i]==1000000){//cerr<<fc[i]<<endl;//cerr<<i<<" "<<fc[i]<<endl;b[i].set(fc[i]);for (auto j:g[i]) b[j]|=b[i];ans1=add(ans1,(ll)sub(fp(2,b[i].count()),1)*fp(2,tot-b[i].count())%M);ans2=add(ans2,fp(2,tot-b[i].count()));}cout<<ans1<<" "<<ans2<<endl; }轉(zhuǎn)載于:https://www.cnblogs.com/Yuhuger/p/10560512.html
總結(jié)
- 上一篇: 阅读笔记一——java高并发的性能优化
- 下一篇: 解决Maven打包怪异异常:Failed