time limit: 30 sec memory limit: 128 mb
submit: 317 solved: 210
alice想要得到乙個長度為n的序列,序列中的數都是不超過m的正整數,而且這n個數的和是p的倍數。alice還希望
,這n個數中,至少有乙個數是質數。alice想知道,有多少個序列滿足她的要求。
一行三個數,n,m,p。
1<=n<=10^9,1<=m<=2×10^7,1<=p<=100
一行乙個數,滿足alice的要求的序列數量,答案對20170408取模。
3 5 3
33
先是容斥,總答案=所有的方案數
-只有合數的方案數。
可以推出暴力的dp方程:
f[i][j]代表長度為i,
modp為j
的方案數
f[i][(j+k)%p]+=f[i-1][j]。
然後這樣的複雜度是o(n*m*p),20
分。
考慮優化,發現對於每個i的轉移都是一樣的,所以可以用矩陣快速冪。
設a為轉移矩陣,發現每乙個
j都可以轉移到
j+k這個位置,
a[j][j+k]+1
。
這樣暴力構矩陣複雜度為o(m*p),80
分。
還可以優化,發現有很多地方可以記憶化,所以可以先預處理出1-m每個數中
p的每個剩餘系的數量,然後直接加進去即可。
複雜度o(m)。100分。
1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7#define maxn 20000010
8#define mod 20170408
9#define ll long long
10using
namespace
std;
11 ll a[110][110][2],b[110][110][2],s[110][110
];12
int su[maxn/10],he[maxn],s1[110],s2[110
];13
ll n,m,p;
14bool
bj[maxn];
15void mul(int a1,int
b1)24
void mul1(int a1,int
b1)33
intmain()
3450 bj[1]=1;51
for(int i=2;i<=m;i++)58}
59for(int i=1;i<=m;i++) if(bj[i])b[0][i%p][0]++;
60for(int i=1;i<=m;i++) if(bj[i])s2[i%p]++;
61for(int i=0;i)
62for(int j=0;j)
63 b[j][(j+i)%p][1]+=s2[i];
64 mi=n-1;65
while
(mi)
70 printf("
%lld
",(a[0][0][0]-b[0][0][0]+mod)%mod);
71return0;
72 }
Sdoi2017 序列計數
alice想要得到乙個長度為n的序列,序列中的數都是不超過m的正整數,而且這n個數的和是p的倍數。alice還希望 這n個數中,至少有乙個數是質數。alice想知道,有多少個序列滿足她的要求。一行三個數,n,m,p。1 n 10 9,1 m 2 10 7,1 p 100 一行乙個數,滿足alice的...
SDOI2017 序列計數
這道題非常的迷幻 首先我們要容斥 考慮記 dp i j 表示前 i 位 p j 的方案數 g i j 表示前 i 位只用合數 p j 的方案數 於是可以考慮最暴力的 dp 是 o nm p 的 但是並沒必要 我們可以提前處理 1 m 這些數 p 的值,用這些值來轉移就好了 也就是額外記乙個 cnt ...
SDOI2017 序列計數
alice 想要得到乙個長度為 n 的正整數序列 滿足 alice 想知道,有多少個序列滿足她的要求。由於題目有 n 個數 和 有否質數 這三個主要限制,因此 設 f i,j,1 0 表示前 i 個數,和為 j 是否有了乙個質數。列出樸素 dp 方程 f i,j,0 sum f i 1,j k,0 ...