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躺了队友一把上了点分,复习模电、离散,完成数据结构作业,啥也没做。