Sdoi2017 序列計數

2022-05-08 04:21:08 字數 1794 閱讀 3647

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 ...