题解
这道题直接暴力计算是行不通的。2mn复杂度远超题目限制。而这是一道计数题,我们可以通过考虑求解每个数在经过一次操作后所产生的贡献,然后每个点求和即为每次答案的解。具体做法为:
设fi为每次操作后极大字段的右端点为i时的序列个数。
当i=r时,我们发现ar!=ar+1,该点必定会产生1的贡献,而第i次操作前序列个数为2i-1,∴fr=fr+2i-1。
当i=l-1时,与上述同理,fl-1=fl-1+2i-1。
当i>=l&&i<r时,不会对答案产生贡献。∴fi=fi。
当i>r || i<l-1时,由于未对这些点进行操作,只是将它们复制了一遍。∴fi=2fi。
#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
using namespace std;
typedef long long LL;
const int mod=20050321;
const int maxn=2e3+10;
int f[maxn],p[maxn];
int main(){
int n,m,l,r;
scanf("%d%d",&n,&m);
p[0]=1;
for(int i=1;i<=2000;i++){
p[i]=p[i-1]*2%mod;
}
f[n]=1;
int cnt=0;
while(m--){
scanf("%d%d",&l,&r);
cnt++;
int ans=0;
for(int i=1;i<l-1;i++) f[i]=2*f[i]%mod;
for(int i=r+1;i<=n;i++) f[i]=2*f[i]%mod;
f[l-1]=(f[l-1]+p[cnt-1])%mod;
f[r]=(f[r]+p[cnt-1])%mod;
for(int i=1;i<=n;i++) {
//cout<<f[i]<<" ";
ans=(ans+f[i])%mod;
}
//cout<<endl;
printf("%d\n",ans);
}
}