1. 程式人生 > >[EOJ Monthly 2018.10][C. 痛苦的 01 矩陣]

[EOJ Monthly 2018.10][C. 痛苦的 01 矩陣]

long long tar splay tps sca 反轉 aps printf blank

題目鏈接:C. 痛苦的 01 矩陣

題目大意:原題說的很清楚了,不需要簡化_(:з」∠)_

題解:設\(r_i\)為第\(i\)行中0的個數,\(c_j\)為第\(j\)列中0的個數,\(f_{i,j}\)代表對應格子是否為0,則有\(cost(i,j)=r_i+c_j-f_{i,j}\),\((cost(i,j))^2=r_i^2+c_j^2+f_{i,j}+2r_ic_j-2f_{i,j}(r_i+c_j)\)

$$\sum_{i=1}^n \sum_{j=1}^n \left( cost(i,j) \right)^2 = \sum_{i=1}^n (r_i^2+c_i^2)+\sum_{i=1}^n \sum_{j=1}^nf_{i,j}+2(\sum_{i=1}^nr_i)(\sum_{j=1}^nc_j)-2f_{i,j}\sum_{i=1}^n \sum_{j=1}^n(r_i+c_j)$$

   初始狀態下,\(ans=n^2*(2n-1)^2, r_i=c_i=n\),給出\(k\)個為1的方格可以看做進行\(k\)次反轉操作,之後把式子中的每一項一一對應地進行修改就好了

技術分享圖片
#include<bits/stdc++.h>
using namespace std;
#define N 200001
#define LL long long
#define MOD 1000000007
LL n,k,q,x,y,u,v,r[N],sr[N],c[N],sc[N],ans;
set<LL>s;
void add(LL x,LL y)
{
    s.insert(x*N+y);
    r[x]
--,c[y]--; ans+=MOD-n*(2ll*r[x]+1)%MOD,ans%=MOD; ans+=MOD-n*(2ll*c[y]+1)%MOD,ans%=MOD; ans+=MOD-1,ans%=MOD; ans+=2ll*(MOD-sc[n]+MOD-sr[n]+1),ans%=MOD; ans+=2ll*(r[x]+1+c[y]+1)%MOD,ans%=MOD; ans+=2ll*r[x]%MOD+2ll*c[y]%MOD,ans%=MOD; sc[n]--,sr[n]--; } void del(LL x,LL y) { sc[n]
++,sr[n]++; ans+=MOD-(2ll*r[x]%MOD+2ll*c[y]%MOD)%MOD,ans%=MOD; ans+=MOD-(2ll*(r[x]+1+c[y]+1)%MOD)%MOD,ans%=MOD; ans+=2ll*(sc[n]+sr[n]-1)%MOD,ans%=MOD; ans++,ans%=MOD; ans+=n*(2ll*c[y]+1)%MOD,ans%=MOD; ans+=n*(2ll*r[x]+1)%MOD,ans%=MOD; r[x]++,c[y]++; s.erase(x*N+y); } int main() { scanf("%lld%lld%lld",&n,&k,&q); for(LL i=1;i<=n;i++) { r[i]=c[i]=n; sr[i]=(sr[i-1]+r[i])%MOD; sc[i]=(sc[i-1]+c[i])%MOD; } ans=4ll*n*n-4ll*n+1,ans%=MOD; ans*=n*n%MOD,ans%=MOD; for(LL i=1;i<=k;i++) scanf("%lld%lld",&x,&y),add(x,y); printf("%lld\n",ans); for(LL i=1;i<=q;i++) { scanf("%lld%lld",&u,&v); if(s.count(u*N+v))del(u,v); else add(u,v); printf("%lld\n",ans); } return 0; }
View Code

[EOJ Monthly 2018.10][C. 痛苦的 01 矩陣]