考慮暴力,當n≤
30 時,素數有2 3 5 7 11 13 17 19 23 29,一共10個,狀壓dp可行,f[i][j]表示每個人選數的狀態,然後暴力轉移就好了,複雜度o(
22n)
。然後我就想不出來了……
有乙個常用到的性質就是,對於任何乙個數字
x ,其大於x√
的約數只能有乙個或者沒有,利用這個性質,可以做這道題。
⌊500−−
−√⌋=
22 ,而小於等於22的最大的素數是19,從1到19一共只有8個素數。
可以只壓這8個素數,f[
i][j
] 表示第乙個人的選數狀態為i,第二個人為j的方案數。 將[
2,500]
的所有數分解質因數,大於19的素數最多有乙個,記下來,記作gp[i](giant prime),小素數們壓進二進位制數,記作tp[i](tiny primes)。
接下來是轉移。
對於gp相等的數,我們劃分到一組裡去單獨dp,因為這一組中只能讓乙個人選數,乙個人選了另乙個人就不能再這組裡選了。
對於乙個組,其giant prime是相同的,令g[
i][j
] 表示已經考慮了組中的所有數和前面做完的組的所有數,強制讓第乙個人選擇這個組中的數(乙個數不選的情況也納入考慮),第二個人不能選,這樣的方案數。
初始狀態g[
i][j
]=f[
i][j
] 那麼我們每次加入組中的乙個數
x ,令k=
tp[x
],轉移就是g[
ibit
ork]
[j]+
=g[i
][j]
(當ib
itan
dk==0
),注意迴圈順序要倒序。
做完一組之後,要將
g 和
f陣列合併,f[
i][j
]=g[
i][j
]+g[
j][i
]−f[
i][j
] ,減去f[
i][j
] 是因為兩個人都啥也不選的情況重複了。
這樣有bug,沒有大素數的那一組不能這樣轉移,這樣轉移方案數會變少,因為這一組中只要兩個人不選相同的數字就行,和前面不一樣。
這時直接f[
ibit
ork]
+=f[
i][j
] ,f[
i][j
bito
rk]+
=f[i
][j]
答案就是所有狀態加起來。
//狀壓dp
#include
#include
#define maxn 1000
#define ll long long
using namespace std;
ll n, p, f[maxn][maxn], g[maxn][maxn], tp[maxn], hp[maxn], mark[maxn], prime[maxn],
num[maxn], h[maxn][maxn];
bool cmp(ll a, ll b)
}for(i=2;i<=n;i++)
for(i=2;i<=n;i++)num[i]=i;
sort(num+2,num+n+1,cmp);
}void dp()
}for(i=0;i<256;i++)for(j=0;j<256;j++)f[i][j]=(g[i][j]+g[j][i]-f[i][j])%p;
}else}}
}for(i=0;i<256;i++)for(j=0;j<256;j++)ans=(ans+f[i][j])%p;
printf("%lld",((ans%p)+p)%p);
}int main()
NOI2015 洛谷P2150 壽司晚宴
為了慶祝noi的成功開幕,主辦方為大家準備了一場壽司晚宴。小g和小w作為參加noi的選手,也被邀請參加了壽司晚宴。在晚宴上,主辦方為大家提供了n 1種不同的壽司,編號1,2,3,n 1,其中第種壽司的美味度為i 1 即壽司的美味度為從2到n 現在小g和小w希望每人選一些壽司種類來品嚐,他們規定一種品...
p2150 NOI2015 壽司晚宴
傳送門 分析 我們發現對於大於 sqrt n 的數每個數最多只會包含乙個 所以我們把每個數按照大質數的大小從小到大排序 我們知道對於一種大質數只能被同乙個人取 所以f1表示被a取,f2表示被b取 最終答案就是這兩個的答案減去啥都不去的答案 因為啥都不去會被重覆記錄兩次 對於小質數則直接狀壓轉移即可 ...
洛谷P2172 bzoj 2150 部落戰爭
lanzerb的部落在a國的上部,他們不滿天寒地凍的環境,於是準備向a國的下部征戰來獲得更大的領土。a國是乙個m n的矩陣,其中某些地方是城鎮,某些地方是高山深澗無人居住。lanzerb把自己的部落分成若干支軍隊,他們約定 每支軍隊可以從任意乙個城鎮出發,並只能從上往向下征戰,不能回頭。途中只能經過...