這道題非常的迷幻
首先我們要容斥
考慮記\(dp[i][j]\)表示前\(i\)位\(\%p=j\)的方案數
\(g[i][j]\)表示前\(i\)位只用合數\(\%p=j\)的方案數
於是可以考慮最暴力的\(dp\)是\(o(nm^*p)\)的
但是並沒必要
我們可以提前處理\(1-m\)這些數\(\%p\)的值,用這些值來轉移就好了
也就是額外記乙個\(cnt[i]\)表示\(\%p\)為\(i\)的數量和\(comp[i]\)表示\(\%p\)為\(i\)的合數的數量
於是就沒必要列舉\(1-m\)轉移了
複雜度變成\(o(np^2)\)
實際上這個序列的生成與位置無關
也就是說我們可以倍增的處理
\(dp[n][j]\)可以由\(dp[n/2][j]\)來直接轉移
於是遞迴做就好了
複雜度\(o(p^2\log n)\)
然而因為轉移的形式是乙個卷積的模樣
所以是可以做到\(o(p\log p\log n)\)的
但是出題人又不卡,就沒寫...
#includeusing namespace std;
#define rep( i, s, t ) for( register int i = s; i <= t; ++ i )
#define re register
#define int long long
int read()
while(cc >= '0' && cc <= '9') cn = cn * 10 + cc - '0', cc = getchar();
return cn * flus;
}const int p = 20170408 ;
const int n = 2000000 + 5 ;
const int m = 100 + 5 ;
const int r = 2 * 1e7 + 5 ;
int n, m, p, dp[2][m], g[2][m], cnt[m], comp[m], ed ;
int pr[n], top;
bool isp[r];
void init() }}
void f( int x, int w )
f( x / 2, w ^ 1 ) ;
rep( j, 0, ed ) dp[w][j] = 0, g[w][j] = 0 ;
rep( j, 0, ed ) rep( k, 0, ed )
dp[w][j] = ( dp[w ^ 1][k] * dp[w ^ 1][(p + j - k) % p] % p + dp[w][j] ) % p ;
rep( j, 0, ed ) rep( k, 0, ed )
g[w][j] = ( g[w ^ 1][k] * g[w ^ 1][(p + j - k) % p] % p + g[w][j] ) % p ;
if( x & 1 )
}signed main()
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 序列計數
time limit 30 sec memory limit 128 mb submit 317 solved 210 alice想要得到乙個長度為n的序列,序列中的數都是不超過m的正整數,而且這n個數的和是p的倍數。alice還希望 這n個數中,至少有乙個數是質數。alice想知道,有多少個序列滿...
SDOI2017 序列計數
alice 想要得到乙個長度為 n 的正整數序列 滿足 alice 想知道,有多少個序列滿足她的要求。由於題目有 n 個數 和 有否質數 這三個主要限制,因此 設 f i,j,1 0 表示前 i 個數,和為 j 是否有了乙個質數。列出樸素 dp 方程 f i,j,0 sum f i 1,j k,0 ...