题目描述
给定一个长度为 n的序列 a,初始都是 0,和一个正整数 k。
现有 (q) 次操作,每次操作给定 (i,v),表示给序列 a的后缀 (a_{[i,n]}) 加上 v。
每次操作后,请你输出 所有数在序列中出现次数的 k次方和 对 20051131取模的结果。
20051131 是质数。
输入格式
第一行三个整数 n,q,k。
接下来 q 行,每行两个整数,表示这次操作的 i,v。
输出格式
q行,每行一个整数,表示这次操作之后所有数在序列中出现次数的 k 次方和对 20051131 取模的值。
输入输出样例
输入 #1
5 5 2
1 1
2 1
3 1
4 1
5 1
输出 #1
25
17
11
7
5
说明/提示
第一次操作后,有 5个 1,答案为 (5^2=25)
第二次操作后,有 1 个 1 和 4 个 2,答案为 (1^2+4^2=17)
类似的,答案分别为 (1^2+1^2+3^2=11,1^2+1^2+1^2+2^2=7,5 imes 1^2=5)
(Subtask 1(20 pts):n,qleq 2 imes 10^3)
(Subtask 2(40 pts):nleq 2 imes 10^3)
(Subtask 3(40 pts):无特殊限制)
(对 100\% 的数据,保证 1leq n,v,kleq 20051130,1leq qleq 5 imes 10^5,1leq ileq n)
题目解析
水题
因为修改区间为([i,n]),所以显然序列(a)的([1,n])项可以划分为单调递增的连续块
形如(1,1,2,2,3,3,4,4,4)
所以维护连续相同区间的左边界,每次修改时,查找左边界小于等于(i)的最大值,以(i)为断点划分为2段,重新计算,并插入新的左边界(i),新的区间即为([x,i))
注意小坑:当(i)与左边界(x)相同时,要删除原来的(x)在插入新的左边界(i),因为他们代表的是同一个区间的左边界(不存在区间([x,x)))
这里使用STL的set方便进行排序查找删除操作
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include<set>
using namespace std;
typedef long long ll;
set<int> s;
int Mod=20051131;
ll ans;
ll qpow(ll x,int k){
ll res=1;
while (k){
if (k&1) res=res*x%Mod;
x=x*x%Mod;
k>>=1;
}
return res;
}
int main(){
int n,q,k,v,x;
cin>>n>>q>>k;
ans=qpow(n,k);
s.insert(1);
s.insert(n+1);
for (int i=1;i<=q;i++){
scanf("%d %d",&x,&v);
set<int>::iterator it;
it=s.lower_bound(x);
int l=*it,r=*(++it);
if (l>x) {
r=*(--it);l=*(--it);
}
//cout<<l<<endl;
ans=(ans-qpow(r-l,k)+Mod)%Mod;
ans=((ans+qpow(x-l,k))%Mod+qpow(r-x,k))%Mod;
if (x==l) s.erase(l);
s.insert(x);
printf("%lld
",ans);
}
}