题解 传统题

传送门

因为没时间写了只记个大概思路
先转为求 \(\sum(m^n-f(ans\leqslant i))\)\(f\) 为方案数
然后求这个 \(f\)
感觉题比较神仙我几乎就是在复述所以就直接截题解了
红色的是笔记
image
image
然后拆后面这个东西(前面“更好看”那一步并不知道如何想到)
似乎有推导方法
考虑从 \(n-ik\) 个球中选出 \(j\) 个,再从中选 \(k\) 个,再在 \(j\) 个中选一个不染,剩下的用 \(m-1\) 种颜色染色
于是可以组合意义优化掉那个 \(\sum\)
直接从 \(n-ik\) 中选 \(k\) 个,然后讨论一下那个特殊球在不在这 \(k\) 个里
剩下的若选中有 \(m-1\) 种颜色,还有可能不选,一共 \(m\) 种情况
所以方案数是 \(m^{n-ik-k}\)(其实题解少了个组合数)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 300010
#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, m;
ll mod;

// namespace force{
// 	ll f[N][N], g[N][N], h[N][N], ans;
// 	void solve() {
// 		for (int i=1; i<=n; ++i) f[i][i]=m;
// 		for (int i=1; i<=n; ++i) {
// 			for (int j=1; j<=i; ++j) {
// 				for (int k=1; k<=(n-i); ++k) {
// 					f[i+k][max(j, k)]=(f[i+k][max(j, k)]+f[i][j]*(m-1))%mod;
// 				}
// 			}
// 		}
// 		for (int i=1; i<=n; ++i) ans=(ans+f[n][i]*i)%mod;
// 		printf("%lld\n", ans);
// 	}
// }

// namespace task1{
// 	ll f[N][N], g[N][N], h[N][N], ans;
// 	void solve() {
// 		for (int i=1; i<=n; ++i) {
// 			for (int j=1; j<i; ++j) {
// 				f[i][j]=(g[i-j][j]+h[i-1][j]-h[i-j][j])*(m-1)%mod;
// 				g[i][j]=(g[i][j-1]+f[i][j])%mod;
// 				h[i][j]=(h[i-1][j]+f[i][j])%mod;
// 			}
// 			f[i][i]=m;
// 			g[i][i]=(g[i][i-1]+f[i][i])%mod;
// 			h[i][i]=(h[i-1][i]+f[i][i])%mod;
// 			for (int j=i+1; j<=n; ++j) g[i][j]=g[i][j-1], h[i][j]=h[i-1][j];
// 		}
// 		// cout<<"f: "; for (int i=1; i<=n; ++i) cout<<f[n][i]<<' '; cout<<endl;
// 		for (int i=1; i<=n; ++i) ans=(ans+f[n][i]*i)%mod;
// 		printf("%lld\n", ans);
// 	}
// }

namespace task{
	ll fac[N], inv1[N], inv2[N], pw1[N], pw2[N], ans;
	inline ll C(int n, int k) {return n<k?0:fac[n]*inv2[k]%mod*inv2[n-k]%mod;}
	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;}
	void solve() {
		pw1[0]=pw2[0]=1; fac[0]=fac[1]=1; inv1[0]=inv1[1]=1; inv2[0]=inv2[1]=1;
		for (int i=1; i<=n; ++i) pw1[i]=pw1[i-1]*(m-1)%mod;
		for (int i=1; i<=n; ++i) pw2[i]=pw2[i-1]*m%mod;
		for (int i=2; i<=n; ++i) fac[i]=fac[i-1]*i%mod;
		for (int i=2; i<=n; ++i) inv1[i]=(mod-mod/i)*inv1[mod%i]%mod;
		for (int i=2; i<=n; ++i) inv2[i]=inv2[i-1]*inv1[i]%mod;
		for (int i=0; i<n; ++i)
			for (int k=0; (i+1)*k<=n; ++k) {
				// ll tem2=C(n-i*k, k)*(((k>0)?(k%mod*qpow(m-1, k-1)%mod*qpow(m, n-i*k-k)):0) + ((n-i*k-k-1>=0)?(qpow(m-1, k)*(n-i*k-k)%mod*qpow(m, n-i*k-k-1)):0))%mod;
				ans=(ans+(k&1?-1:1)*inv1[n-i*k]*( C(n-i*k, k)*(((k>0)?(k%mod*pw1[k-1]%mod*pw2[n-i*k-k]%mod):0) + ((n-i*k-k-1>=0)?(pw1[k]*(n-i*k-k)%mod*pw2[n-i*k-k-1]%mod):0))%mod ))%mod;
				// ans=(ans+(k&1?-1:1)*inv1[n-i*k]*( C(n-i*k, k)*(((k>0)?(k%mod*qpow(m-1, k-1)%mod*qpow(m, n-i*k-k)%mod):0) + ((n-i*k-k-1>=0)?(qpow(m-1, k)*(n-i*k-k)%mod*qpow(m, n-i*k-k-1)%mod):0))%mod ))%mod;
				// ll tem=0;
				// for (int j=k; j<=n; ++j) if (j>0) tem=(tem+qpow(m-1, j-1)*C(j, k)%mod*C(n-i*k, j)%mod*j)%mod;
				// cout<<"tem: "<<i<<' '<<k<<' '<<tem<<' '<<(tem2%mod+mod)%mod<<endl;
				// ans=(ans+(k&1?-1:1)*inv1[n-i*k]*tem)%mod;
			}
		printf("%lld\n", ((qpow(m, n)*n%mod-ans*m%mod)%mod+mod)%mod);
		exit(0);
	}
}

signed main()
{
	n=read(); m=read(); mod=read();
	// task1::solve();
	task::solve();
	
	return 0;
}
posted @ 2022-01-11 21:26  Administrator-09  阅读(0)  评论(0编辑  收藏  举报