题解 简单题

传送门

以为是个找规律题……然而规律找不到

考试的时候试图把成二倍的数合并成一个块,然后跑DP
然而我块的端点判定炸了,我以为它应该是质数,但其实它只要是个奇数就行了……
然后链长不会超过log,因为链上第 \(k\) 个点是 \(2^{k-1}p\)
于是暴力枚举链长,发现每个链一定会对最终可能的集合大小产生 \(\frac{k}{2}\) 的贡献
而奇数链会可选地多产生1的贡献
统计这些额外的贡献,组合数即可
今天头很疼,今天的题解几乎都水了

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 10000020
#define ll long long 
#define reg register int 
#define fir first
#define sec second
#define make make_pair
//#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 ll read() {
	ll 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;
}

ll n, m; int q;
const ll p=10000019;

namespace force{
	ll ans[N], tot;
	void solve() {
		int lim=1<<n;
		for (reg s=0,s2,cnt; s<lim; ++s) {
			for (reg i=1; i<=n; ++i) 
				if (s&(1<<(i-1))) {
					if (i<<1<=n && s&(1<<((i<<1)-1))) goto jump;
				}
				else {
					if (i<<1<=n && !(s&(1<<((i<<1)-1)))) goto jump;
				}
			s2=s; cnt=0;
			if (s2) do {s2&=s2-1; ++cnt;} while (s2);
			//cout<<"s: "<<cnt<<' '<<bitset<10>(s)<<endl;
			++ans[cnt]; ++tot;
			jump: ;
		}
		for (reg i=1; i<=q; ++i) printf("%lld\n", ans[read()]%p);
		//cout<<"tot: "<<tot<<endl;
		cout<<"ans: "<<endl;; for (int i=1; i<=n; ++i) cout<<i<<": "<<ans[i]<<endl;
		exit(0);
	}
}

namespace task1{
	int pri[N], pcnt, top;
	pair<int, int> siz[N];
	ll dp[5010][5010];
	bool npri[N];
	void solve() {
		int lim=n/2;
		for (int i=2; i<=lim; ++i) {
			if (!npri[i]) pri[++pcnt]=i;
			for (int j=1; j<=pcnt&&i*pri[j]<=lim; ++j) {
				npri[i*pri[j]]=1;
				if (!(i%pri[j])) break;
			}
		}
		//cout<<"pcnt: "<<pcnt<<endl;
		for (int i=1; i<=pcnt; ++i) {
			int t=floor(log(floor(1.0*n/(1.0*pri[i]))+1e-8)/log(2))+1;
			//cout<<"t: "<<t<<endl;
			siz[++top]=make(t/2, t-t/2);
		}
		++siz[1].fir;// ++siz[1].sec;
		lim=(n+1)/2 - ((n)/2)/2;
		cout<<"lim: "<<lim<<endl;
		for (int i=1; i<=lim; ++i) siz[++top]=make(1, 0);
		//cout<<"pcnt: "<<pcnt<<endl;
		//cout<<"top: "<<top<<endl;
		for (int i=1; i<=top; ++i) cout<<siz[i].fir<<' '<<siz[i].sec<<endl; cout<<endl;
		dp[0][0]=1; lim=1<<((n+1)/2-1);
		for (int i=1; i<=top; ++i) {
			for (int j=1; j<=n; ++j) {
				//dp[i][j] = dp[i-1][j];
				if (j>=siz[i].fir) dp[i][j]=(dp[i][j]+dp[i-1][j-siz[i].fir])%p;
				if (j>=siz[i].sec) dp[i][j]=(dp[i][j]+dp[i-1][j-siz[i].sec])%p;
			//if (i!=top) dp[i][0]=1;
			}
		}
		//for (int k=1; k<=top; ++k) for (int i=1; i<=n; ++i) cout<<i<<": "<<dp[k][i]<<endl;
		//cout<<"ans: "<<endl; for (int i=1; i<=n; ++i) cout<<i<<": "<<dp[top][i]<<endl;
		for (int i=1; i<=q; ++i) {
			printf("%lld\n", dp[top][read()]);
		}
		exit(0);
	}
}

namespace task{
	ll fac[N], inv[N];
	inline ll C(ll n, ll k) {return n<k?0:fac[n]*inv[k]%p*inv[n-k]%p;}
	inline ll lucas(ll n, ll k) {return k?C(n%p, k%p)*lucas(n/p, k/p):1ll;}
	ll qpow(ll a, ll b) {
		ll ans=1;
		while (b) {
			if (b&1) ans=ans*a%p;
			a=a*a%p; b>>=1;
		}
		return ans;
	}
	void solve() {
		fac[0]=fac[1]=1; inv[0]=inv[1]=1;
		for (int i=2; i<=p; ++i) fac[i]=fac[i-1]*i%p;
		for (int i=2; i<=p; ++i) inv[i]=(p-p/i)*inv[p%i]%p;
		for (int i=2; i<=p; ++i) inv[i]=inv[i-1]*inv[i]%p;
		ll sum=0, lim=log(n)/log(2)+1, t, dlt=0, base=1;
		for (int k=1; k<=lim; ++k) {
			//cout<<"k: "<<k<<endl;
			t = ((n/(1ll<<(k-1)))+1)/2 - ((n/(1ll<<k))+1)/2;
			//cout<<"t: "<<t<<endl;
			sum+=t*(k/2);
			if (k&1) dlt+=t;
			else base=base*qpow(2, t)%p;
		}
		//cout<<"sum: "<<sum<<' '<<dlt<<endl;
		for (int i=1; i<=q; ++i) {
			m=read();
			if (m<sum || m>sum+dlt) puts("0");
			else printf("%lld\n", base*lucas(dlt, m-sum)%p);
		}
		exit(0);
	}
}

signed main()
{
	n=read(); q=read();
	//if (n<=20) force::solve();
	//else task1::solve();
	//force::solve();
	task::solve();
	
	return 0;
}
posted @ 2021-08-17 21:28  Administrator-09  阅读(10)  评论(0编辑  收藏  举报