题解 简单题
以为是个找规律题……然而规律找不到
考试的时候试图把成二倍的数合并成一个块,然后跑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;
}