ECNU 2018.10 月赛 C(数学统计)

原题: https://acm.ecnu.edu.cn/contest/113/problem/C/

题意:

01矩阵, C o s t ( i , j ) Cost(i,j) 为i行和j列的0的个数, S u m = i = 1 n j = 1 n C o s t ( i , j ) Sum=\sum_{i=1}^n\sum_{j=1}^nCost(i,j)
每次操作为反转一个位置的数,求开始的Sum和每次操作后的Sum

解析:

R i R_i 为i行的0数量, C j C_j 为j列的0数量, B i j B_{ij} 表示ij位置是否为0, A A 为矩阵中0的数量
i = 1 n B i j = C j , j = 1 n B i j = R i , i = 1 n C j = j = 1 n R i = A \sum_{i=1}^nB_{ij}=C_j,\sum_{j=1}^nB_{ij}=R_i,\sum_{i=1}^nC_{j}=\sum_{j=1}^nR_{i}=A
那么接下来化简题目表达式:
S u m = i = 1 n j = 1 n C o s t 2 ( i , j ) = i = 1 n j = 1 n ( R i + C j B i j ) 2 = i = 1 n [ ( R i + C 1 B i 1 ) 2 + ( R i + C n B i n ) 2 ] = i = 1 n [ ( R i + C 1 ) 2 + B i 1 2 B i 1 ( R i + C 1 ) +   ] = i = 1 n [ ( n R i 2 + ( C 1 2 + C n 2 ) + 2 R i A ) + R i 2 R i 2 j = 1 n 2 B i j C j ] Sum=\sum_{i=1}^n\sum_{j=1}^nCost^2(i,j)\\=\sum_{i=1}^n\sum_{j=1}^n(R_i+C_j-B_{ij})^2\\=\sum_{i=1}^n[(R_i+C_1-B_{i1})^2+\dots(R_i+C_n-B_{in})^2]\\=\sum_{i=1}^n[(R_i+C_1)^2+B_{i1}-2B_{i1}(R_i+C_1)+\dots]\\=\sum_{i=1}^n[(nR_i^2+(C_1^2+\dots C_n^2)+2R_iA)+R_i-2R_i^2-\sum_{j=1}^n2B_{ij}C_j]
= ( n 2 ) i = 1 n R i 2 + n j = 1 n C j 2 + 2 A 2 + A 2 i = 1 n j = 1 n B i j C j = ( n 2 ) i = 1 n R i 2 + ( n 2 ) j = 1 n C j 2 + 2 A 2 + A =(n-2)\sum_{i=1}^nR_i^2+n\sum_{j=1}^nC_j^2+2A^2+A-2\sum_{i=1}^n\sum_{j=1}^nB_{ij}C_j\\=(n-2)\sum_{i=1}^nR_i^2+(n-2)\sum_{j=1}^nC_j^2+2A^2+A

所以每次修改的时候找到原来的 R , C , A R,C,A ,再算出现在的比较计算就是答案。判断为1或0可以用set,注意每次操作后需要维护set。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+5;
const LL mod=1e9+7;
LL a[N],b[N];

struct node{
    int x,y;
}e[N];
set<int>S[N];

int main(){
    LL n,k,q;
    scanf("%lld%lld%lld",&n,&k,&q);
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    for(int i=1;i<=k;i++){
        int x,y;scanf("%d%d",&x,&y);
        e[i].x=x,e[i].y=y;
        S[x].insert(y);
        a[y]++,b[x]++;
    }
    for(int i=1;i<=n;i++)a[i]=n-a[i],b[i]=n-b[i];//num of 0

    LL A=(n*n-k)%mod;
    LL All=(2*A*A+A)%mod;
    for(int i=1;i<=n;i++)All=(All+(n-2)*a[i]*a[i]%mod+(n-2)*b[i]*b[i]%mod)%mod;
    printf("%lld\n",All);

    while(q--){
        int x,y;
        scanf("%d%d",&x,&y);

        LL pre=((n-2)*a[y]*a[y]%mod+(n-2)*b[x]*b[x]%mod+2*A*A%mod+A)%mod;
        LL now;
        if(S[x].find(y)==S[x].end()){//0->1
            now=((n-2)*(a[y]-1)%mod*(a[y]-1)%mod+(n-2)*(b[x]-1)%mod*(b[x]-1)%mod+2*(A-1)*(A-1)%mod+A-1)%mod;
            A--,a[y]--,b[x]--;
            S[x].insert(y);
        }
        else{
            now=((n-2)*(a[y]+1)%mod*(a[y]+1)%mod+(n-2)*(b[x]+1)%mod*(b[x]+1)%mod+2*(A+1)*(A+1)%mod+A+1)%mod;
            A++,a[y]++,b[x]++;
            S[x].erase(y);
        }
        All=((All+now-pre)%mod+mod)%mod;
        printf("%lld\n",All);
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/84109441