• 「SWTR07」IOI 2077


    挺 SB 的,要不是我睡过头赛时就切了。

    我习惯用 \(C(n,m)\) 表示 \(n\) 个数选 \(m\) 个数的方案。

    因为 \(a_i\) 升序,显然按 \([l,k),(k,r]\) 去分。

    考虑暴力,然而每种方案数很难算。换个角度,考虑一个数的贡献次数。

    挺显然的,假如 \(i\in[l,k)\) 那么就是 \(C(k-l,m-1)\times C(r-k,m)\),即左右各选 \(m\) 包含这个数的方案数。 \(i \in (k,r]\) 同理。

    再考虑 \(a_k\),显然每种方案都有它。

    暴力 Code:

    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <map>
    #include <ctime>
    #define ll long long
    using namespace std;
    int rd() {
    	int f=1,sum=0; char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    ll lrd() {
    	ll f=1,sum=0; char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    
    #define mod 998244353
    #define int ll
    
    int fpow(int x,int y) {
    	int res=1;
    	while(y) {
    		if(y&1) res=res*x%mod;
    		x=x*x%mod; y>>=1;
    	}
    	return res;
    }
    #define N (int)(2e6+5)
    int n,a[N],jie[N],djie[N],sum[N],m;
    
    int C(int n,int m) {
    	if(m>n||m<0) return 0;
    	return jie[n]*djie[m]%mod*djie[n-m]%mod;
    }
    
    int SUM(int l,int r) {
    	return (((sum[r]-sum[l-1])%mod)+mod)%mod;
    }
    
    signed main() {
    	jie[0]=djie[0]=1;
    	for(int i=1;i<=(int)(2e6);i++) jie[i]=jie[i-1]*i%mod,djie[i]=fpow(jie[i],mod-2);
    	rd(); n=rd(); m=rd(); for(int i=1;i<=n;i++) a[i]=rd(),sum[i]=(sum[i-1]+a[i])%mod;
    	int ans=0;
    	for(int mmm=1;mmm<=m;mmm++) {
    		int l=rd(),r=rd(),k=rd();
    		int qwq=(r-l)/2,res=0;
    		for(int i=0;i<=qwq;i++) {
    			int r1=0,x=C(k-l-1,i-1)*C(r-k,i)%mod; //cout<<i<<" "<<x<<endl;
    			r1+=SUM(l,k-1)*x%mod;
    			x=C(k-l,i)*C(r-k-1,i-1)%mod;
    			r1+=SUM(k+1,r)*x%mod;
    			x=C(k-l,i)*C(r-k,i)%mod;
    			r1+=x*a[k]%mod; r1=r1*fpow(x,mod-2)%mod; r1=(r1%mod+mod)%mod;
    		//	cout<<i<<" "<<r1<<endl;
    			res=(res+r1)%mod;
    		}
    		res=res*fpow(qwq+1,mod-2)%mod; res=(res%mod+mod)%mod;
    	//	cout<<res<<endl;
    		ans^=res;
    	}
    	printf("%lld",ans);
    	return 0;
    }
    

    显然我们不能枚举 \(m\),考虑对式子拆开,单独看一个小部分。

    假如我们看

    \[\dfrac{SUM(l,k-1)\times C(k-l-1,i-1)\times C(r-k,i)}{C(k-l,i)\times C(r-k,i)} \]

    发现可以化掉

    \[SUM(l,k-1)*i*(k-l) \]

    那一切都挺显然的了。

    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <map>
    #include <ctime>
    #define ll long long
    using namespace std;
    int rd() {
    	int f=1,sum=0; char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    ll lrd() {
    	ll f=1,sum=0; char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    void pr(int x) {
    	if(x<0) {putchar('-');x=-x;}
    	if(x>9) pr(x/10);
    	putchar(x%10+'0');
    }
    const int mod=998244353;
    #define int ll
    
    int fpow(int x,int y) {
    	int res=1; x%=mod;
    	while(y) {
    		if(y&1) res=res*x%mod;
    		x=x*x%mod; y>>=1;
    	}
    	return res;
    }
    #define N (int)(2e6+5)
    int n,a[N],sum[N],INV[N],m;
    
    int SUM(int l,int r) {
    	return (sum[r]-sum[l-1])%mod;
    }
    
    int SUM1(int l,int r) {
    	return (r+l)*(r-l+1)%mod*fpow(2,mod-2)%mod;
    }
    
    int check(int n,int m) {
    	return n>=m;
    }
    
    signed main() {
    	rd(); n=rd(); m=rd(); for(int i=1;i<=n;i++) a[i]=rd(),sum[i]=(sum[i-1]+a[i])%mod;
    	INV[0]=INV[1]=1; for(int i=2;i<=(int)(2e6);i++) INV[i]=INV[mod%i]*(mod-mod/i)%mod;
    	int ans=0;
    	for(int mmm=1;mmm<=m;mmm++) {
    		int l=rd(),r=rd(),k=rd();
    		int qwq=(r-l)>>1,res=0;
    		int qaq=min(qwq,min(k-l,r-k));
    		res+=SUM(l,k-1)*SUM1(0,qaq)%mod*INV[k-l]%mod; res%=mod; 
    		res+=SUM(k+1,r)*SUM1(0,qaq)%mod*INV[r-k]%mod; res%=mod;
    		res+=(qaq+1)*a[k]%mod; res%=mod;
    		res=res*INV[qwq+1]%mod; res=(res%mod+mod)%mod;
    	//	cout<<res<<endl;
    		ans^=res;
    	}
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    aspnet_Membership_SetPassword
    FlipView使用
    结构之法字符串及链表的探索编程之美第3章
    window和linux下svn的使用
    【算法导论第13章】红黑树
    【算法导论】第16章贪心算法
    【算法导论】第15章动态规划
    ubuntu11.04下myeclipse开发环境的搭建(jdk6+tomcat6+myeclipse8.0+mysql)
    【matlab】在vc6.0中调用matlab中的正态分布产生随机数
    gnome/gtk+开发环境搭建
  • 原文地址:https://www.cnblogs.com/xugangfan/p/15872347.html
Copyright © 2020-2023  润新知