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