[ZJOI2017]树状数组

点我跳转

  • 前几天和海亮一起考前年浙江省选,难度确实太大了,连暴力都不会打QAQ。
  • 这道题是个跟概率有关的题目,概率还是菜,一看概率题就不想做了。先仔细分析一波再看看,其实50分挺好拿。
  • 看了可怜的代码,你发现他把树状数组求前缀写成了求后缀。因为本题所有的答案都在mod 2意义下,所以当可怜求区间和(l,r)的时候,只是原来的r变成了l-1。因此可怜答案正确的概率就是l-1与r相同的概率。
  • 还有一种特殊情况,就是l=1的时候。可怜求的是r~n的和,真正需要求的是1-r的和,这时候可怜正确的情况是1到r-1与r+1到n相同。
  • 那么现在就是求概率了,我之前以为每次修改的时候暴力修改一下整个区间内所有概率就好了。但是显然不对。你比如说,对区间(1,3)修改了一次,此时问1和3都是1的概率。如果我那种sb算法,这个概率求出来不为0。但是显然只修改了一次,不可能都是1的。
  • 所以,我们只考虑l-1和r相等和不相等的概率,每次询问的时候,把所有的修改操作跑一遍,这样不会矛盾。
  • 这只是50分的写法,菜鸡暂时不知道二维线段树怎么写。(洛谷只有42分)。
Coding
#include
#define ll long long
using namespace std;
const int mod=998244353;
const int N=1e4+100;
int n,m,cnt,lc[N],rc[N],inv[N],f[N][2];
int power(int a,int b)
{int ans=1;for(;b;b>>=1,a=1LL*a*a%mod)if(b&1)ans=1LL*ans*a%mod;return ans;}
void work(int l,int r){
	f[0][0]=1;
	for(int i=1;i<=cnt;++i){
		int px=0,p=power(rc[i]-lc[i]+1,mod-2);
		if(l){
			if(lc[i]<=l&&l<=rc[i]) px+=p;
			if(lc[i]<=r&&r<=rc[i]) px+=p;
			px%=mod;
		}else{
			if(r<lc[i]) px=1;
			else if(rc[i]<r) px=1;
			else{
				px=(1-p+mod)%mod;
			}
		}
		for(int j=0;j<=1;++j){
            f[i][j&1]=0;
            f[i][j&1]=(f[i][j&1]+1LL*f[i-1][j-1&1]*px%mod)%mod;
            f[i][j&1]=(f[i][j&1]+1LL*f[i-1][j&1]*((1-px)%mod+mod)%mod)%mod;
        }
	}cout<<f[cnt][0]<<endl;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i){
		int op,l,r;scanf("%d%d%d",&op,&l,&r);
		if(op==1){
			lc[++cnt]=l,rc[cnt]=r;
		}else{
			work(l-1,r);
		}
	}
}

你可能感兴趣的:(数据结构)