problem
Day1 T1
给定一个长度为 n n n 的整数数列 { a n } \{a_n\} {an},有 q q q 次操作,操作有 6 6 6 种,分别为:单点赋值,全局加,全局乘,全局赋值,单点查值,全局求和。
操作的读入有点鬼畜啊,建议仔细读一下。
数据范围: 1 ≤ n ≤ 1 0 9 1≤n≤10^9 1≤n≤109, 1 ≤ q ≤ 1 0 7 1\le q\le 10^7 1≤q≤107。
solution
我们先分析一下数据范围。操作有 1 0 7 10^7 107 个,应该是 O ( 1 ) O(1) O(1) 完成每个操作; n n n 又有 1 0 9 10^9 109 那么大,可以排除线段树等数据结构。
然后发现题目的特性:好像只有单点操作和全局操作,并没有区间的操作。
我们可以按照线段树的思路,记一 a d d , m u l , s u m add,mul,sum add,mul,sum,表示全局加,全局乘,全局求和。
那么 2 , 3 , 4 , 6 2,3,4,6 2,3,4,6 操作就是套路,不多说了。想一想怎么做单点操作。
对于 1 1 1,也可以开个 unordered_map 直接做,要记录一下最后一个更改此位置的时间。
那么对于 5 5 5,我们可以取 a x a_x ax(就是最后一次单点赋值和最后一次区间赋值中时间靠后的那次),答案就是 a x × m u l + a d d a_x\times mul+add ax×mul+add。那这也提示我们,单点赋值是时不能直接赋 v a l val val,应该是 v a l − a d d m u l \frac{val-add}{mul} mulval−add。
因此我们还要处理处 m u l mul mul 的逆元。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<tr1/unordered_map>
#define N 100005
#define P 10000019
using namespace std;
using namespace tr1;
int n,q,t,add,mul=1,sum,Last,ans;
int a[105],b[105],inv[P];
unordered_map<int,int>val,Time;
struct query{int op,x,y;}Q[N];
int Add(int x,int y) {return x+y>P?x+y-P:x+y;}
int Dec(int x,int y) {return x-y<0?x-y+P:x-y;}
int Mul(int x,int y) {return 1ll*x*y%P;}
void solve(int i,int T){
if(Q[i].op==6) ans=Add(ans,sum);
else if(Q[i].op==2) add=Add(add,Q[i].x),sum=Add(sum,Mul(Q[i].x,n));
else if(Q[i].op==3) mul=Mul(mul,Q[i].x),add=Mul(add,Q[i].x),sum=Mul(sum,Q[i].x);
else if(Q[i].op==4) add=0,mul=1,sum=Mul(Q[i].x,n),val[0]=Q[i].x,Last=T;
else if(Q[i].op==5){
if(Time[Q[i].x]<=Last) ans=Add(ans,Add(Mul(val[0],mul),add));
else ans=Add(ans,Add(Mul(val[Q[i].x],mul),add));
}
else{
if(Time[Q[i].x]<=Last) sum=Dec(sum,Add(Mul(val[0],mul),add));
else sum=Dec(sum,Add(Mul(val[Q[i].x],mul),add));
sum=Add(sum,Q[i].y),Time[Q[i].x]=T,val[Q[i].x]=Mul(Dec(Q[i].y,add),inv[mul]);
}
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=q;++i){
scanf("%d",&Q[i].op);
if(Q[i].op==6) continue;
if(Q[i].op==1) scanf("%d%d",&Q[i].x,&Q[i].y),Q[i].y=Add(Q[i].y%P,P);
else scanf("%d",&Q[i].x),Q[i].x=Add(Q[i].x%P,P);
}
scanf("%d",&t);
for(int i=1;i<=t;++i)
scanf("%d%d",&a[i],&b[i]);
inv[1]=1;
for(int i=2;i<P;++i) inv[i]=Mul(P-P/i,inv[P%i]);
for(int i=1;i<=t;++i)
for(int j=1;j<=q;++j)
solve((a[i]+1ll*j*b[i])%q+1,(i-1)*q+j);
printf("%d",ans);
return 0;
}