在遭受了巨大的精神打擊後,我決定了,要做乙個壓行的好孩子!!!
部落格如果有不對之處,請一定要指出啊啊啊啊啊謝謝謝謝謝大佬!!!
我們首先可以寫出乙個遞推式:
f [a
+c][
b∗d取
模mod
]=f[
a][b
]∗f[
c][d
]f[a+c][b*d取模mod]=f[a][b]*f[c][d]
f[a+c]
[b∗d
取模mo
d]=f
[a][
b]∗f
[c][
d]可以發現,這個格式並不是卷積。那我們怎麼辦呢?
我們知道,有ai∗
aj=a
i+
ja^i*a^j=a^
ai∗aj=
ai+j
,那我們可以將式子轉化為原根i次方。然後我們就可以用卷積來做了。
然後我再來說一下打法:solve函式類似快速冪,每一次乘法相當於新增乙個數(就像dp外層的1至n的迴圈)。而g陣列則表示相應的餘數對應的方案數。
最後,因為運算時不帶取模,我們需要再加上a[i
+m−1
]a[i+m-1]
a[i+m−
1]。為什麼加m-1而不是加m?因為此處保證m為質數,也就是說m的尤拉函式是m-1。(如有不懂尤拉函式的童鞋們可以去康康 )那麼,我們可以保證的是,0到m-2構成的數,在m-1及之後相同的長度還有一毛一樣的。而這取模m-1就是相同的餘數。為什麼只加一次呢?這要看我們變換的範圍。
再最後,我們知道m-1並不一定是階。這就可能有0到m-2之間有重複餘數但不相加的情況。為什麼可以直接輸出呢?仔細看看我們的初始化,我們將輸入的值為餘數處理。實際上,這些不同的編號(i)代表的是同乙個數。
awsl感覺自己在口胡。不知所言。
所以又到了激動人心的上**環節。
#include
#include
using
namespace std;
const
int mod =
1004535809
, n =
50002
;int n, m, x, len, inv, lim =
1, rev[n]
, ori, l, pos =-1
, a[n]
, b[n]
, g[n]
, f[n]
;bool vis[n]
;int
qkpow
(int x,
int y,
int p)
return res;
}int
cal(
const
int p)if(
! flag)
return i;}}
void
swap
(int
&x,int
&y)void
ntt(
int*t,
const
int op)}}
}void
mul(
int*g,
int*f)
void
solve
(int y)
}void
init
(const
int lim)
for(
int i =
0; i < lim;
++ i) rev[i]
=(rev[i >>1]
>>1)
|((i &1)
<<
(l -1)
);}int
main()
init
(m -
1<<1)
;solve
(n);
if(pos !=-1
) cout << g[pos]
% mod;
else cout <<
"0";
putchar
('\n');
return0;
}
謝謝! SDOI2015 序列統計
time limit 30 sec memory limit 128 mb submit 1829 solved 870 submit status discuss 小c有乙個集合s,裡面的元素都是小於m的非負整數。他用程式編寫了乙個數列生成器,可以生成乙個長度為n的數 列,數列中的每個數都屬於集合...
SDOI2015 序列統計
description 小c有乙個集合s,裡面的元素都是小於m的非負整數。他用程式編寫了乙個數列生成器,可以生成乙個長度為n的數列,數列中的每個數都屬於集合s。小c用這個生成器生成了許多這樣的數列。但是小c有乙個問題需要你的幫助 給定整數x,求所有可以生成出的,且滿足數列中所有數的乘積mod m的值...
SDOI2015 序列統計
點此看題 第一次寫ntt text ntt,被搞自閉了。0x01 樸素dp 設f i j f i j f i j 為選i ii個數乘積為j jj的方案數,轉移如下 f 2 i j f i k f i j inv k f 2i j f i k times f i j times inv k f 2i ...