J:https://ac.nowcoder.com/acm/contest/7858/J
题意:已知一个n * n的二维数组每个数的值为 ,再给你q次查询,每次查询都会要你输出一行或一列的元素的和,每次查询完后,对应行列的所有元素都会变成0。
思路:最先想到的必然是暴力,首先把相应的值填出来,每次查询都把对应行列的和求出来,同时把相应元素变成0。这样一来复杂度就是O(qn)的了。这肯定不行,我们再来想,开两个数组分别记录行列的和,这个和可以借助等差数列求和公式。每次查询就把相应的数据输出,但是每次查询后,就要维护一个长度为n的数组,这依然不行。但是这给我们提供了一个思路。如果这次是对行的查询(设为第x行),那么影响到的就是所有列的和。每一列都要减去x和自己的编号,也就是减去x+j。如果查询了很多行,那么每一列要减去的就是所有被查询过的行编号的和,同时还要减去被查询过的行的数量个j。同理,列也是这样。同时还有一点就是每一行(列)的和其实也是一个公差为n的等差数列。至于那些行(列)被查询过,可以用一个map来维护。至此答案也就出来了。具体细节看看代码。
一定要开longlong 。不开longlong得见祖宗的。
//team yglance+xhwl+TTD
//author: CN.TTDragon
#include<bits/stdc++.h>
typedef long long ll;
const ll mod=1e9+7;
const ll maxn=1e6+7;
const double pi=acos(-1);
using namespace std;
ll hang[maxn];
ll ans=0;
//对于每一行每一列而言,可以借助等差数列来求和
map <ll,ll> RR;
map <ll,ll> LL;
ll beichahang,beichalie;//被查询过的数量
ll sumbeichahang,sumbeichalie; //被查询过的编号的和
int main()
{
ios::sync_with_stdio(false);
ll n,m;
cin>>n>>m;
ll temp=(2+n+1)*n/2;//第一行/列的和,其他行列的和可以用它来当首项,方法很多,不需要吊死在我这颗树上
//cout<<temp<<endl;
char c;
ll x;//这里要开ll,后续运算直接用的它,用int会WA的
beichahang=0,beichalie=0;
sumbeichahang=0,sumbeichalie=0;
while(m--)
{
ans=0;
cin>>c>>x;
if(c=='R')
{
if(RR[x]==1)//这一行之前被查询过
{
ans=0;
}
else
{
RR[x]=1;
beichahang++;//被查询过的行数多了一个
sumbeichahang+=x;//被查询过的行编号的和多了x
ans+=temp+(x-1)*n;//一开始会设置成没有被查询过的值,后续减掉被查询过的列带来的影响就好。计算方法是上方的粗体。
ans-=beichalie*x;
ans-=sumbeichalie;
}
}
else//列是同理的。
{
if(LL[x]==1)//这一列之前被查询过
{
ans=0;
}
else
{
LL[x]=1;
beichalie++;
sumbeichalie+=x;
ans+=temp+(x-1)*n;
ans-=beichahang*x;
ans-=sumbeichahang;
}
}
cout<<ans<<endl;
}
return 0;
}
写在后面:
昨日,与室友去独墅湖体验炳麟图书馆,摸鱼之际想起正事。没开ll,对拍到自闭。
国庆节过去了,除了CF躺了队友一把上了点分,复习模电、离散,完成数据结构作业,啥也没做。

京公网安备 11010502036488号