其他分享
首页 > 其他分享> > 5.4 NOI模拟

5.4 NOI模拟

作者:互联网

\(5.4\ NOI\)模拟

\(T1\)

想到分讨,但是暴力输出一下方案之后有很多特别的情况要讨论,就弃了...

假设\(a\)是原序列,\(b\)是我们得到的序列

设\(i\)是最长公共前缀,\(j\)是最长公共后缀

我们假设询问的是整个序列,若\(i+j=n-1\)那我们的方案数是\(m-1\),较为显然

否则\(i+j<=n-2\)

首先比较显然的是,由于已知串确定,可以根据最长公共前后缀长度进行分类,即可不重不漏的计算每一种情况

那么\(a[i+1]\)和\(a[n-j]\)至少有一个出现在最长公共序列(可能取出来的公共序列不是同一个)里

我们枚举\(i,j\)

假设\(i+j<=n-2\)

\(Sit_1:a[i+1]\neq a[i+2]\)可以增加\(m-1\)种情况

\(Sit_2:a[n-j]\neq a[n-j-1]\)可以增加\(m-1\)种情况

\(Sit_3:a[i+1]\neq a[i+2]\)且\(a[n-j]\neq a[n-j-1]\)那么就\(a[i+1...n-j-2]=a[i+3...n-j],\)可增加\(1\)种情况

我们的答案是\(Sit_1+Sit_2-Sit_3\)

就是说我们可能出现\(1,2\)重复计算情况减去一部分就好了

那么暴力的话可以枚举\(i,j\)进行计算,可以发现,前两种情况,我们可以合并统计

对于第三种情况,我们只需要找到所有满足条件的\(i,j\)即可

那么枚举\(i\)那么\(j>=n-i-2-lcp(a[i+1..n],a[i+3...n])\)既满足\(a[n-j]\neq a[n-j-1],\)用\(Sit_3\)反证即可

合并的意思是,还是说 颜色块数\(\times n\times (m-1)\) 就好了,就没有那么多的分讨了

\(lcp\)求和的话发现有单调性,可使用双指针,复杂度降到\(O(n)\)

\(T2\)

\(Give\ up\)

\(T3\)

一开始想的是枚举最大值计算有多少种情况,发现在有重复数字时候寄了

错误式子是

\(\large \frac{\sum_{max}max\times C(Num_{min},k-1)}{C(Num,k)}\)

很容易发现一件事,就是我们枚举了最大值可是并不是知道最大值是谁,因为这个是有标号的

那么我们假定同样大小编号大的比较大的话,就能保证不重复了

设\(a\)为降序排序序列,设\(b\)为升序排序序列

我们考虑答案计算

\(\sum_{i=l}^r C(r-i,k-1)\times a[i]\)

这样复杂度不是很优

考场上看到了\(\sum k<=100000,\)感觉\(k\)的种类不是很多,就想着全部预处理出来,没去想根号分治...

考虑进行根号分治

我们要计算区间\((l,r)\)

此时序列降序

我们提前预处理\(dp[i][j]\)表示\(k=i\)时,\(\sum_{z=1}^j C(j-z,k-1)\times b[z],\)也就是\(1-j\)区间选\(k\)个数字最大值的总和

我们现在要求\(\sum_{z=l}^r C(r-z,k-1)\times b[z]=dp[k][r]-\sum_{z=1}^{l-1}C(r-z,k-1)\times b[z]\)

考虑把他转化到\(dp[k][l-1]\)上

\(\sum_{z=1}^{l-1}C(r-z,k-1)\times b[z]=\sum_{j}dp[j][l-1]\times C(r-l+1,k-j)\)

组合意义比较显然,假设我们的贡献在前面,我们可以枚举前面选了多少个,然后后面任选的减去就好了,然后就\(hhh\)了

\(dp[i][j]=dp[i-1][j-1]+dp[i][j-1]\)

把式子拆开

\(\large \sum_{z=1}^j C(j-z,i-1)b[z]=\sum_{z=1}^{j-1} C((j-1)-z,i-2)b[z]+\sum_{z=1}^{j-1} C((j-1)-z,i-1)b[z]\)

较为显然,直接是组合数递推式的样子

#include<bits/stdc++.h>
#define int long long
#define mod 998244353 
#define MAXN 100005
#define Lim 300
using namespace std;
int inv[MAXN],fac[MAXN],b[MAXN],a[MAXN],n,q;
int dp[Lim+5][MAXN];
inline int rd(){
    int r = 0 , w = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0') {if(ch == '-') w = -1; ch = getchar();} 
    while(ch >='0' && ch <='9') {r = r * 10 + ch -'0'; ch = getchar();}
    return r * w;
}
void Init()
{
	 inv[0]=fac[0]=1;
	 inv[1]=fac[1]=1;
     for(int i=2;i<MAXN;i++)
     {
     	 fac[i]=(fac[i-1]*i)%mod;
     	 inv[i]=(mod-mod/i)*inv[mod%i]%mod;
	 }
	 for(int i=1;i<MAXN;i++)
	 {
	 	 inv[i]=(inv[i-1]*inv[i])%mod;
	 }
}
int C(int n,int m)
{
	if(m<0||m>n) return 0;
	return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int my_pow(int a,int b)
{
	int res=1;
	while(b)
	{
		  if(b&1)
		  {
		  	 res=res*a%mod;
		  }
		  a=a*a%mod;
		  b>>=1;
	}
	return res;
}
signed main()
{
	scanf("%lld%lld",&n,&q);
	Init();
	for(int i=1;i<=n;i++)
	{
		a[i]=rd();
        b[i]=a[i];
	}
	sort(a+1,a+1+n);
	sort(b+1,b+1+n);
	reverse(a+1,a+1+n);
	for(int i=1;i<=n;i++) dp[1][i]=(dp[1][i-1]+a[i])%mod;
	for(int i=2;i<=Lim;i++)
	{
		for(int j=1;j<=n;j++)
		{
			dp[i][j]=(dp[i-1][j-1]+dp[i][j-1])%mod;
		}
	}
//	for(int i=1;i<=n;i++)
//	{
//		cout<<b[i]<<" ";
//	}
//	cout<<"\n";
	for(int i=1,l,r,k;i<=q;i++)
	{
//		cout<<"shu: "<<l<<" "<<r<<"\n";
        l=rd();
        r=rd();
        k=rd();
		l=lower_bound(b+1,b+1+n,l)-b;
		r=upper_bound(b+1,b+1+n,r)-b-1;
//		cout<<"Sit: "<<l<<" "<<r<<"\n";
        printf("%lld ",r-l+1);
		swap(l,r);
		l=n-l+1;
		r=n-r+1;
        int Ans=0; 
        if(k==0)
        {
           puts("0");
		   continue;
		}
		if(k>r-l+1)
		{
			puts("-1");
		    continue;
		}
		if(k>Lim)
		{
			for(int j=l;j<=r;j++)
			{
				Ans=(Ans+C(r-j,k-1)*a[j])%mod;
			}
		}
        else
        {
        	Ans=dp[k][r]%mod;
        	for(int j=1;j<=k;j++)
        	{
        		Ans-=C(r-l+1,k-j)*dp[j][l-1]%mod;
			}
			Ans%=mod;
			Ans+=mod;
			Ans%=mod;
		}
		Ans=(Ans*my_pow(C(r-l+1,k),mod-2)%mod);
		printf("%lld\n",Ans);
//		cout<<Ans<<"\n";
	}
	return 0;
}
/*
7 3
83 74 100 89 95 79 72
90 100 3
80 89 1
70 79 2
*/

标签:ch,5.4,NOI,Sit,int,sum,times,dp,模拟
来源: https://www.cnblogs.com/Eternal-Battle/p/16223248.html