JZOJ 4437. 【HNOI2016模拟4.10】线性代数与逻辑
Description
Input
Output
Sample Input
Sample Output
Data Constraint
Solution
(附:本人第 100 篇博文,為 OI 事業(yè)奮斗,多多支持~)。
這道題的題面讓人感到云里霧里,但是經(jīng)過仔細(xì)的抽絲剝繭之后就會發(fā)現(xiàn)這真“模型”。
首先, X 矩陣是由 Y 向量構(gòu)造出來的: X[i][j]=y[i]?xor?y[j] 。
所以當(dāng) X 矩陣的對角線上存在 1 時,就不合法了,輸出“-1”(異或運算的性質(zhì))。
又由于 X 矩陣的對稱性,我們只需處理對角線上方的答案,最后乘2即可。
我們發(fā)現(xiàn),如果每一位 A[i][j]=1 的話,因為 A?||?!X=!O ,所以要求 X[i][j]=1 。
所以相當(dāng)于 y[i]≠y[j] ,則點 i 向點 j 連一條無向邊,表示點 i 和點 j 為對立點。
這樣便構(gòu)出了一張二分圖(若有奇環(huán)則判為“-1”),用 Friend-Enemy 并查集 維護(hù)出聯(lián)通塊。
那么最后答案是所有聯(lián)通塊的 0 的個數(shù)乘 1 的個數(shù) 。
為了保證答案最優(yōu),對于這些連通塊,我們可以做一遍類似背包的 O(N2)DP:
設(shè) F[i][j] 表示做到第 i 個連通塊、0 的個數(shù)為 j 的 1 的最大個數(shù) ,轉(zhuǎn)移顯然。
由于 X 取過反 , 1 的最大個數(shù)即為所求。
又由于開始的狀態(tài)有 1 ,會計算重復(fù),我們減去算出的 連邊條數(shù)(意義相同) 即可。
那么連邊、DP復(fù)雜度相等,這樣總時間復(fù)雜度即為 O(N2) 。
Code
#include<cstdio> #include<cstring> #define clr(x,y) memset(x,y,sizeof(x)); using namespace std; const int N=1001; int n,tot,num; int first[N],next[N<<1],en[N<<1]; int f[N][N],g[N],h[N][2],fa[N]; bool judge; bool a[N][N]; inline int read() {int X=0,w=1; char ch=0;while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();return X*w; } inline int max(int x,int y) {return x>y?x:y; } inline int get(int x) {if(fa[x]==x) return x;return fa[x]=get(fa[x]); } inline void insert(int x,int y) {next[++tot]=first[x];first[x]=tot;en[tot]=y; } inline void init_link() {tot=num=0;clr(first,0);clr(g,-1);clr(h,0);clr(f,-1);for(int i=1;i<=n;i++) fa[i]=i;for(int i=1;i<n;i++)for(int j=i+1;j<=n;j++)if(a[i][j]){insert(i,j);insert(j,i);int f1=get(i),f2=get(j);if(f1!=f2) fa[f1]=f2;} } inline void dfs(int x,int y) {h[num][g[x]]++;for(int i=first[x];i;i=next[i])if(en[i]!=y){if(g[en[i]]==g[x]){judge=true;return;}if(g[en[i]]!=-1) continue;g[en[i]]=g[x]^1;dfs(en[i],x);if(judge) return;} } inline void dp() {int ans=f[0][0]=0;for(int i=1;i<=num;i++)for(int j=0;j<=n;j++){int x=h[i][0],y=h[i][1];if(j>=x && f[i-1][j-x]!=-1) f[i][j]=max(f[i][j],f[i-1][j-x]+y);if(j>=y && f[i-1][j-y]!=-1) f[i][j]=max(f[i][j],f[i-1][j-y]+x);}for(int j=0;j<=n;j++) ans=max(ans,f[num][j]*j);printf("%d\n",(ans<<1)-tot); } inline void work() {n=read();for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) a[i][j]=read();for(int i=1;i<=n;i++)if(a[i][i]){printf("-1\n");return;}init_link();for(int i=1;i<=n;i++)if(get(i)==i){judge=g[i]=0,num++;dfs(i,0);if(judge){printf("-1\n");return;}}dp(); } int main() {int T=read();while(T--) work();return 0; }總結(jié)
以上是生活随笔為你收集整理的JZOJ 4437. 【HNOI2016模拟4.10】线性代数与逻辑的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ 2038: [2009国家集训
- 下一篇: JZOJ 5230. 【NOIP2017