题目传送门
题目大意:一个矩阵,每次查询一行或一列的和,再将其删去。
大致思路如下:
既然行与列对称,我们只考虑删行即可。如果删掉了第 i i i 行,很明显地,第 i i i 行与第 j j j 列只有 ( i , j ) (i,j) (i,j) 一个交点,而它的值就是行号 ( i ) (i) (i) 加列号 ( j ) (j) (j),所以这一操作会让第 j j j 列的元素和减少 i + j i+j i+j。
这样的话,可以展开以下推导:
我们还是只分析行。假设所有删列操作的列号分别为 x 1 , x 2 , … , x k x_1,x_2,\dots,x_k x1,x2,…,xk 。
易得第 i \texttt{i} i 行的初始元素和为
( i + 1 ) + ( i + 2 ) + ⋯ + ( i + n ) = ( i + 1 + i + n ) ∗ n / 2 (i+1)+(i+2)+\dots+(i+n)=(i+1+i+n)*n/2 (i+1)+(i+2)+⋯+(i+n)=(i+1+i+n)∗n/2
= i ∗ n + n ∗ ( n + 1 ) / 2 \kern13.5em=i*n+n*(n+1)/2 =i∗n+n∗(n+1)/2。
那么,根据上面推导的规律, k \texttt{k} k 次删除之后,元素和就会变为下面这个柿子:
i ∗ n − ( i + x 1 ) − ( i + x 2 ) − ⋯ − ( i + x k ) + n ∗ ( n + 1 ) / 2 i*n-(i+x_1)-(i+x_2)-\dots-(i+x_k)+n*(n+1)/2 i∗n−(i+x1)−(i+x2)−⋯−(i+xk)+n∗(n+1)/2,化简得
i ∗ ( n − k ) − ( x 1 + x 2 + ⋯ + x n ) + n ∗ ( n + 1 ) / 2 i*(n-k)-(x_1+x_2+\dots+x_n)+n*(n+1)/2 i∗(n−k)−(x1+x2+⋯+xn)+n∗(n+1)/2。
所以,我们只需要两个变量保存剩余列数 & \& & 每次删列的索引和即可直接计算出剩余元素和了。
巴拉巴拉讲了一大堆,该 跑路 贴标程了:
#include<bits/stdc++.h>
using namespace std;
long long n,m,r,l,a,b,x,sum;//l保存删列索引和,r保存删行索引和,
bool vis1[1000001],vis2[1000001];//a保存剩余列数,b保存剩余行数
char c;
int main(){
cin>>n>>m;
sum=(n+1)*n/2,a=b=n;
for(int i=1;i<=m;i++){
cin>>c>>x;
if(c=='R'){
if(vis1[x])cout<<0<<endl;//如果删掉了直接输出0
else{
vis1[x]=1;//记录这行被删了
cout<<x*a-l+sum<<endl;//公式
b--;
r+=x;
}
}else{//同上
if(vis2[x])cout<<0<<endl;
else{
vis2[x]=1;
cout<<x*b-r+sum<<endl;
a--;
l+=x;
}
}
}
return 0;
}