CF886E Maximum Element

不合法就是序列 \(\max\) 前面存在 \(a_i>a_j,j\in[i+1,i+k]\),这个限制不好计数,跟 \(a_i\) 在序列中的相对大小有关,也跟位置有关。

考虑总情况 - 合法情况。

要返回正确的最大值,则 \(\max\) 前面的部分不能提前推出,明显是要对这种序列计数。

\(f_i\) 表示长度为 \(i\) 且找不到最大值的序列数。则该序列中的 \(\max\) 必定在 \([i-k+1,i]\) 中,否则必定会提前推出。

枚举 \(\max\) 的位置。

\[f_i=\sum_{j=i-k+1}^i f_{j-1}(i-j)!{i-1\choose j-1} \]

其中 \(\max\) 前面部分不能提前退出也就是 \(f_{j-1}\),后面部分随便填 \((i-j)!\),还要在除去 \(\max\) 剩下的数中选 \(j-1\) 个数到前面 \({i-1\choose j-1}\)

有了 \(f\),就能对答案计数了,枚举原序列 \(\max\) 的位置。

\[ans=n!-\sum_{j=1}^n f_{j-1}(n-i)!{n-1\choose j-1} \]

两个式子形式基本一样,但求 \(f\) 的复杂度是 \(O(nk)\) 的。

观察发现这个 \((i-j)!\) 与后面的组合式能消掉,将组合式拆开:

\[f_i=\sum_{j=i-k+1}^i f_{j-1}\frac{(i-1)!}{(j-1)!}=(i-1)!\sum_{j=i-k+1}^i \frac{f_{j-1}}{j-1} \]

显然可以求 \(\frac{f_i}{i}\) 的前缀和优化至 \(O(n)\)

UesugiErii
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#define fin(x) freopen(#x".in","r",stdin)
#define fout(x) freopen(#x".out","w",stdout)
#define fr(x) fin(x),fout(x);
#define Fr(x,y) fin(x),fout(y)
#define INPUT(_1,_2,FILE,...) FILE
#define IO(...) INPUT(__VA_ARGS__,Fr,fr)(__VA_ARGS__)
using namespace std;
using namespace __gnu_pbds;
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define ll long long
#define ull unsigned long long
#define intz(x,y) memset((x),(y),sizeof((x)))
char *p1,*p2,buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define tup(x) array<int,(x)>
inline ll read(){
    ll x=0,f=1;char ch=nc();
    while(ch<48||ch>57){if(ch=='-')f=-1;ch=nc();}
    while(ch>=48&&ch<=57)x=x*10+ch-48,ch=nc();
   	return x*f;
}
//void write(int x){cout<<x<<' ';}
//void write(pii x){cout<<"P("<<x.fi<<','<<x.se<<")\n";}
//void write(vector<auto>x){for(auto i:x)write(i);cout<<'\n';}
//void write(auto *a,int l,int r){for(int i=l;i<=r;i++)write(a[i]);cout<<'\n';}
inline ll lowbit(ll x){return x&-x;}
#define pcount(x) __builtin_popcount(x)
inline void cmx(auto &x,ll y){if(y>x)x=y;}
inline void cmn(auto &x,ll y){if(y<x)x=y;}
inline int max(vector<int>w){int res=-1e9;for(int i:w)cmx(res,i);return res;}
const int mod=1e9+7;
ll qp(ll x,int y){ll res=1;for(;y;x=x*x%mod,y>>=1)if(y&1)res=res*x%mod;return res;}
const int N=1e6+5;
#define int ll
int fac[N],ifac[N],f[N],s[N];
int C(int x,int y){return x<y?0:fac[x]*ifac[y]%mod*ifac[x-y]%mod;}
inline void UesugiErii(){
	int n,k;cin>>n>>k;
	for(int i=fac[0]=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
	ifac[n]=qp(fac[n],mod-2);
	for(int i=n;i;i--)ifac[i-1]=ifac[i]*i%mod;
	f[0]=s[0]=1;
	for(int i=1;i<=n;i++)
		f[i]=(s[i-1]+mod-(i>=k+1?s[i-k-1]:0))%mod*fac[i-1]%mod,
		s[i]=(s[i-1]+f[i]*ifac[i]%mod)%mod;
	int ans=0;
	for(int i=1;i<=n;i++)
		(ans+=C(n-1,i-1)*f[i-1]%mod*fac[n-i]%mod)%=mod;
	cout<<(fac[n]+mod-ans)%mod;
}
signed main(){
	//IO();//cfast;
	int _=1;//cin>>_;
	for(;_;_--)UesugiErii();
	return 0;
}
posted @ 2025-12-11 11:17  Uesugi1  阅读(8)  评论(0)    收藏  举报