题解 Hill of Sunflowers

传送门

读错题了,以为是每种可能的 b 数组中的所有 LIS 都能分别产生一次贡献
最后发现模不出来样例,手玩了个 \(n=3\) 跑路

发现 \(n\) 较小,可以直接枚举最终 b 数组的大小关系
具体地,可以枚举出所有可能的 \(b_i\) 的最终排名 \(p_i\)
则问题变为每个 \(b\) 有个 \(b_i\leqslant lim_i\) 的限制,要给所有 \(b_i\) 赋权值
\(f_{i, j}\) 为给第 \(i\) 大数赋值且值在离散化后第 \(j\) 个区间中的方案数
转移枚举上一个不在此区间内的数,组合数把中间的数放到当前区间里即可
复杂度 \(O(4683n^4)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 10
#define ll long long
#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
int a[N];
const int mod=1e9+7;
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}

namespace force{
	int b[N], f[N], ans;
	void calc() {
		f[0]=0;
		int max_len=0;
		for (int i=1; i<=n; ++i) {
			int maxn=0;
			for (int j=0; j<i; ++j) if (b[j]<b[i]) maxn=max(maxn, f[j]);
			max_len=max(max_len, f[i]=maxn+1);
		}
		ans=(ans+max_len)%mod;
	}
	void dfs(int u) {
		if (u>n) {calc(); return ;}
		for (int i=1; i<=a[u]; ++i) {
			b[u]=i;
			dfs(u+1);
		}
	}
	void solve() {
		dfs(1);
		ll inv=1;
		for (int i=1; i<=n; ++i) inv=inv*a[i]%mod;
		printf("%lld\n", ans*qpow(inv, mod-2)%mod);
	}
}

namespace task1{
	ll inv[N];
	ll qsum(ll n) {return n*(n+1)%mod*inv[2]%mod;}
	ll C(ll n, ll k) {
		if (n<k) return 0;
		else if (k==2) return n*(n-1)%mod*inv[2]%mod;
		else if (k==3) return n*(n-1)%mod*(n-2)%mod*inv[6]%mod;
		else assert(0);
		return 0;
	}
	ll solve(int a, int b) {return (a*(b-a)%mod+qsum(a-1))%mod;}
	ll solve(int a, int b, int c) {
		ll ans=0;
		ans=(ans+solve(a, b)*(c-b))%mod;
		ans=(ans+C(a, 2)*(b-a))%mod;
		ans=(ans+C(b-a, 2)*a)%mod;
		ans=(ans+C(a, 3))%mod;
		return ans;
	}
	void solve() {
		inv[0]=inv[1]=1;
		for (int i=2; i<=10; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		ll ans=0, all=0, tmp=0;
		if (n==1) ans=a[1];
		else if (n==2) ans=(2*solve(min(a[1], a[2]), a[2])+a[1]*a[2]-solve(min(a[1], a[2]), a[2]))%mod;
		else {
			all=a[1]*a[2]%mod*a[3]%mod;
			if (a[1]<=a[2] && a[2]<=a[3]) {
				//cout<<1<<endl;
				ans=(ans+3*solve(a[1], a[2], a[3]))%mod;
				all=(all-solve(a[1], a[2], a[3]))%mod;
				tmp=(solve(a[1], a[1], a[1])+2*solve(a[1], a[1])+a[1])%mod;
				ans=(ans+tmp)%mod; all=(all-tmp)%mod;
				ans=(ans+2*all)%mod;
			}
			else if (a[1]>=a[2] && a[2]<=a[3]) {
				//cout<<2<<endl;
				ans=(ans+3*solve(a[2], a[2], a[3]))%mod;
				all=(all-solve(a[2], a[2], a[3]))%mod;
				tmp=(solve(a[2], a[2], a[1])+solve(a[2], a[1])+solve(a[2], a[2])+a[2])%mod;
				ans=(ans+tmp)%mod; all=(all-tmp)%mod;
				ans=(ans+2*all)%mod;
			}
			else if (a[1]<=a[2] && a[2]>=a[3]) {
				//cout<<3<<endl;
				ans=(ans+3*solve(min(a[1], a[3]), a[3], a[3]))%mod;
				all=(all-solve(min(a[1], a[3]), a[3], a[3]))%mod;
				tmp=(solve(min(a[1], a[3]), a[1], a[1])+2*solve(min(a[1], a[3]), a[1])+min(a[1], a[3]));
				ans=(ans+tmp)%mod; all=(all-tmp)%mod;
				ans=(ans+2*all)%mod;
			}
			else if (a[1]>=a[2] && a[2]>=a[3]) {
				//cout<<4<<endl;
				ans=(ans+3*solve(a[3], a[3], a[3]))%mod;
				all=(all-solve(a[3], a[3], a[3]))%mod;
				tmp=(solve(a[3], a[2], a[1])+solve(a[3], a[1])+solve(a[3], a[2])+a[3]);
				ans=(ans+tmp)%mod; all=(all-tmp)%mod;
				ans=(ans+2*all)%mod;
			}
		}
		ll prod=1;
		for (int i=1; i<=n; ++i) prod=prod*a[i]%mod;
		printf("%lld\n", (ans*qpow(prod, mod-2)%mod+mod)%mod);
	}
}

namespace task{
	bool vis[N];
	int b[N], p[N], f[N], lim[N], uni[N], usiz;
	ll inv[N], dp[N][N], ans;
	ll C(ll n, int k) {if (n<k) return 0; ll ans=inv[k]; for (ll i=n; i>n-k; --i) ans=ans*i%mod; return ans;}
	ll calc() {
		//cout<<"calc: "; for (int i=1; i<=n; ++i) cout<<p[i]<<' '; cout<<endl;
		int m=0; usiz=0;
		memset(lim, 127, sizeof(lim));
		memset(dp, 0, sizeof(dp));
		for (int i=1; i<=n; ++i) lim[p[i]]=min(lim[p[i]], a[i]), m=max(m, p[i]);
		for (int i=1; i<=n; ++i) uni[++usiz]=lim[p[i]];
		sort(uni+1, uni+usiz+1);
		usiz=unique(uni+1, uni+usiz+1)-uni-1;
		//cout<<"uni: "; for (int i=1; i<=usiz; ++i) cout<<uni[i]<<' '; cout<<endl;
		dp[0][0]=1;
		for (int i=1; i<=m; ++i)
			for (int j=1; j<=usiz&&uni[j]<=lim[i]; ++j) {
				int down=lim[i];
				for (int k=i-1; ~k; --k) {
					down=min(down, lim[k+1]);
					if (down<uni[j]) break;
					for (int l=0; l<j; ++l)
						dp[i][j]=(dp[i][j]+dp[k][l]*C(uni[j]-uni[j-1], i-k))%mod;
				}
			}
		//cout<<"---dp---"<<endl; for (int i=1; i<=m; ++i) {for (int j=1; j<=usiz; ++j) cout<<dp[i][j]<<' '; cout<<endl;}
		ll ans=0;
		for (int i=1; i<=usiz; ++i) ans=(ans+dp[m][i])%mod;
		//cout<<"return: "<<ans<<endl<<endl;
		return ans;
	}
	void dfs(int u) {
		if (u>n) {
			int maxn=0, max_len=0;
			memset(vis, 0, sizeof(vis));
			for (int i=1; i<=n; ++i) vis[p[i]]=1, maxn=max(maxn, p[i]);
			for (int i=maxn; i; --i) if (!vis[i]) return ;
			for (int i=1; i<=n; ++i) {
				int maxn=0;
				for (int j=1; j<i; ++j) if (p[j]<p[i]) maxn=max(maxn, f[j]);
				max_len=max(max_len, f[i]=maxn+1);
			}
			ans=(ans+max_len*calc())%mod;
			return ;
		}
		for (int i=1; i<=n; ++i) p[u]=i, dfs(u+1);
	}
	void solve() {
		inv[0]=inv[1]=1;
		for (int i=2; i<N; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		for (int i=2; i<N; ++i) inv[i]=inv[i-1]*inv[i]%mod;
		dfs(1);
		//cout<<ans<<endl; return ;
		ll prod=1;
		for (int i=1; i<=n; ++i) prod=prod*a[i]%mod;
		printf("%lld\n", (ans*qpow(prod, mod-2)%mod+mod)%mod);
	}
}

signed main()
{
	freopen("hill.in", "r", stdin);
	freopen("hill.out", "w", stdout);

	n=read();
	for (int i=1; i<=n; ++i) a[i]=read()%mod;
	// force::solve();
	task::solve();
	
	return 0;
}
posted @ 2022-02-22 17:01  Administrator-09  阅读(2)  评论(0编辑  收藏  举报