題目鏈結
先考慮暴力\(dp\),\(f[i][j]\)表示前\(i\)個數,數字之和模\(p\)餘\(j\)的方案數。
我們先不考慮必須有質數這個條件,先統計出全部方案。然後再減去沒有質數的方案就行了。
那麼就有\(f[i + 1][(j + k) \% p] += f[i][j](1\le k \le m)\)
然後發現這個其實並不需要\(o(m)\)的轉移,因為\((j + k) \% p\)對於每個餘數來說,最少有\(\lfloor\frac\rfloor\)個。然後有\(m\%p\)個數有\(\lfloor\frac\rfloor + 1\)個.只要對這\(m\%p\)個數單獨處理一下就行了。
然後計算沒有質數的方案數,全部用合數轉移即可。
然後發現這個是可以矩陣優化的。
轉移矩陣的第\(i\)行第\(j\)列表示從\(1 + i\)到\(m+i\)中有多少個數字模\(p\)餘\(j\)。同樣可以計算一下,然後\(o(p^2)\)的列出矩陣。
對於全部用合數轉移的情況,轉移矩陣可以\(o(p\frac)\)轉移,親測吸氧可過
/*
* @author: wxyww
* @date: 2019-02-13 16:22:09
* @last modified time: 2019-02-13 20:51:05
*/#include#include#include#include#include#include#include#includeusing namespace std;
typedef long long ll;
// #define int ll
const int mod = 20170408;
ll read()
while(c>='0'&&c<='9')
return x*f;
}int n,m,p;
namespace bf2
node(int nn,int mm)
node(int nn)
};node operator * (const node &x,const node &y) }}
return c;
}node operator ^ (node x,int y)
int dis[2000003],vis[20000003];
int tot,tmp[2000003];
int js;
void eur() }}
void main()
}for(int i = 0;i < p;++i) for(int j = 0;j < p;++j) c.a[i][j] += m / p;
node ans(0,p - 1);
ans.a[0][0] = 1;
ans = ans * (c ^ n);
int anss = ans.a[0][0];
memset(ans.a,0,sizeof(ans.a));
memset(c.a,0,sizeof(c.a));
ans.a[0][0] = 1;
eur();
for(int i = 0;i < p;++i)
}for(int i = 0;i < p;++i) for(int j = 0;j < p;++j) c.a[i][j] += m / p;
for(int i = 0;i < p;++i)
for(int j = 1;j <= js;++j)
c.a[i][(i + dis[j]) % p]--;
ans = ans * (c ^ n);
cout<<(anss - ans.a[0][0] + mod) % mod;
}}signed main()
BZOJ4818 SDOI2017 序列計數
bzoj luogu alice想要得到乙個長度為 n 的序列,序列中的數都是不超過 m 的正整數,而且這 n 個數的和是 p 的倍數。alice還希望,這 n 個數中,至少有乙個數是質數。alice想知道,有多少個序列滿足她的要求。一行三個數,n,m,p 1 le n le 10 9,1 le m...
BZOJ 4818 Sdoi2017 序列計數
bzoj 4818 sdoi2017 序列計數 矩陣乘法 alice想要得到乙個長度為n的序列,序列中的數都是不超過m的正整數,而且這n個數的和是p的倍數。alice還希望 這n個數中,至少有乙個數是質數。alice想知道,有多少個序列滿足她的要求。一行三個數,n,m,p。1 n 10 9,1 m ...
4818 Sdoi2017 序列計數
4818 sdoi2017 序列計數 time limit 30 sec memory limit 128 mb submit 396 solved 267 submit status discuss description alice想要得到乙個長度為n的序列,序列中的數都是不超過m的正整數,而且...