【WC2017模擬1.22】簡單題
題目大意
給定n,k,求把n!拆分成k個不同的正整數的乘積的方案數。(一種方案的排列仍是一種方案)。答案對
n≤10000 k≤30
時限為4s
分析
這是一道容斥好題。
首先可以不管算重,最終答案除以
接下來考慮如何容斥。k個數互不相同,其實就相當於
如果直接列舉不滿足哪些,顯然會超時。不妨轉換一下:已知條件是形如(x,y)的,表示第x個數≠第y個數。把k個數看成k個點,限制(x,y)看成連線x,y的邊。那麼一個選擇方案相當於選擇一些邊,使其變成許多個聯通塊。
好了,現在可以嘗試列舉每個聯通塊的大小。這就相當於對k的整數拆分。為了避免算重,當前列舉的這一個數必須不小於前一個。跑出來,30能有5000多種拆法。那麼整數拆分的方案數就可以接受了。接下來到下一步。
現在已經確定了k的一個整數拆分方案(即若干個聯通塊大小)。假設有m個聯通塊,第i個大小為
1. 把k個點分配到這些聯通塊的方案數。
2. 對應的分配邊的所有方案對答案的貢獻
3. 拆分
它對答案的貢獻就是三個數的乘積。現在一個個來考慮。
首先是第1部分
這個比較簡單。首先總的排列數有
第2部分
對於每個聯通塊分別考慮。因為一條邊的意義是兩個數相同,所以一個聯通塊裡的所有數都是相等的。那就可以直接考慮容斥係數的總和了。
設
設
首先考慮不合法的。其實就是n個點的不聯通圖。它形成了至少2個聯通塊。列舉編號為1的點所在的聯通塊大小,那麼:
其中
考慮
上面的式子變成:
那麼一個整數拆分方案第2部分的貢獻為
最後是第3部分
首先給n!分解質因數。每個質因子都是相對獨立的,就可以分開考慮。
對於一個質因子,設它共出現了
優化
為了提高執行效率,可能需要一些優化。
1. 遞迴對k進行拆分,然後做揹包時相當於有m個物品。回溯的時候,前m-1個物品的答案要保留,不用每個方案都重新做一次dp
2. 假設k當前剩下x沒有拆分,先列舉到x/2,再直接整個拆分
3. 適當去掉一些模運算
我的程式極限資料跑了3s左右
#include <cstdio>
#include <cstring>
#include <algorithm>
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=10005,M=31,mo=1e9+7,NN=100000;
typedef long long LL;
int n,m,Fac[N],Inv[N],F_Inv[N],g[N],tot,p[N],f[M][NN],cnt[N],st[N],sum,ans;
bool bz[N];
void init()
{
scanf("%d%d",&n,&m);
for (int i=2;i<=n;i++)
{
if (!bz[i]) p[tot++]=i;
for (int j=0;j<tot && i*p[j]<=n;j++)
{
bz[i*p[j]]=1;
if (i%p[j]==0) break;
}
}
for (int i=2;i<=n;i++)
for (int j=0,x=i;j<tot;j++)
for (;x%p[j]==0;x/=p[j]) cnt[j]++;
for (int i=1;i<=tot;i++) st[i]=st[i-1]+cnt[i-1]+1;
Fac[0]=F_Inv[0]=Fac[1]=Inv[1]=F_Inv[1]=1;
for (int i=2;i<=n;i++)
{
Fac[i]=(LL)Fac[i-1]*i%mo;
Inv[i]=(LL)Inv[mo%i]*(mo-mo/i)%mo;
F_Inv[i]=(LL)F_Inv[i-1]*Inv[i]%mo;
}
}
void dfs(int x,int y,int m,int sum,int t)
{
if (m==0)
{
for (int i=0;i<tot;i++) sum=(LL)sum*f[x-1][st[i+1]-1]%mo;
ans=(ans+sum)%mo;
return;
}
if (y>m) return;
for (int i=0;i<tot;i++)
{
for (int j=st[i];j<st[i]+y;j++) f[x][j]=f[x-1][j];
for (int j=st[i]+y;j<st[i+1];j++) f[x][j]=(f[x-1][j]+f[x][j-y])%mo;
}
dfs(x+1,y,m-y,(LL)sum*F_Inv[y]%mo*Inv[t+1]%mo*g[y]%mo,t+1);
if (y==m) return;
for (int k=y+1;k*2<=m;k++)
{
for (int i=0;i<tot;i++)
{
f[x][st[i]+k-1]=f[x-1][st[i]+k-1];
for (int j=st[i]+k;j<st[i+1];j++) f[x][j]=(f[x-1][j]+f[x][j-k])%mo;
}
dfs(x+1,k,m-k,(LL)sum*F_Inv[k]%mo*g[k]%mo,1);
}
for (int i=0;i<tot;i++)
{
for (int j=st[i];j<st[i]+m;j++) f[x][j]=f[x-1][j];
for (int j=st[i]+m;j<st[i+1];j++) f[x][j]=(f[x-1][j]+f[x][j-m])%mo;
}
dfs(x+1,m,0,(LL)sum*F_Inv[m]%mo*g[m]%mo,1);
}
void work()
{
g[1]=1;
for (int i=2;i<=m;i++) g[i]=(-(LL)(i-1)*g[i-1])%mo;
ans=0;
for (int i=0;i<tot;i++) f[0][st[i]]=1;
dfs(1,1,m,Fac[m],0);
ans=(LL)(ans+mo)%mo*F_Inv[m]%mo;
printf("%d\n",ans);
}
int main()
{
//freopen("jdt.in","r",stdin); freopen("jdt.out","w",stdout);
init();
work();
fclose(stdin); fclose(stdout);
return 0;
}
相關推薦
【WC2017模擬1.22】簡單題
題目大意 給定n,k,求把n!拆分成k個不同的正整數的乘積的方案數。(一種方案的排列仍是一種方案)。答案對109+7取模。 n≤10000 k≤30 時限為4s 分析 這是一道容斥好題。 首先可以不管算重,最終答案除以k!即可。 接下來考慮
【GDOI2016模擬4.22】總結
ble 走了 一見 打了 再看 很多 這不 學會 由於 前言 早上,一進機房,發現所有人神情嚴肅,一股(\(da\))(\(ba\))場的氣氛迎面撲來,我一下子意識到:nothing good! 這場比賽結果不是很好,50分; 第一題:感覺上是個神奇的匹配問題,但是,由於
jzoj5919. 【NOIP2018模擬10.22】逛公園(tarjan,二分)
5919. 【NOIP2018模擬10.22】逛公園 Description 琥珀色黃昏像糖在很美的遠方,思念跟影子在傍晚一起被拉長…… Description 小 B 帶著 GF 去逛公園,公園一共有 n 個景點,標號為 1 . . . n。景點之間有 m
JZOJ 5919. 【NOIP2018模擬10.22】逛公園
題目 n條線段 [ l , r
JZOJ5919. 【NOIP2018模擬10.22】逛公園
Description 小 B 帶著 GF 去逛公園,公園一共有 n 個景點,標號為 1 . . . n。景點之間有 m 條路徑相連。 小 B 想選擇編號在一段區間 [l, r] 內的景點來遊玩,但是如果這些景點的誘導子圖形成了環,那麼 GF 將會不高興。 小 B 給出很多個詢問 [x,
JZOJ-senior-5920. 【NOIP2018模擬10.22】風箏
Time Limits: 4000 ms Memory Limits: 524288 KB Description 當一陣風吹來,風箏飛上天空,為了你,而祈禱,而祝福,而感動…… oyiya 在 AK 了 IOI 之後來到了鄉下,在田野中玩耍,放鬆身心。 他發
JZOJ-senior-5921. 【NOIP2018模擬10.22】種花
Time Limits: 2000 ms Memory Limits: 524288 KB Description 院子落葉,跟我的思念厚厚一疊;窗臺蝴蝶,像詩裡紛飛的美麗章節…… Input 小 H
5921. 【NOIP2018模擬10.22】種花
題目大意 因為找不到題面所以就勉為騎♂男C了一張下來 思路 因為題目要求的是最後的總和,所以可以分開每一對a[i]和a[j]來考慮,計算每一對的貢獻 對於每一對數,考慮其位置和出現次數,可以分成幾類出現次數相同的來討論 那麼每一類的貢獻就是 (距離1+距離2+……)*出現次
【NOIP2015模擬10.22】最小代價
前言 本來在比賽上就想到最小生成樹了,但不相信這道題那麼簡單,然後就沒有然後了。。。 題目 給出一幅由n個點m條邊構成的無向帶權圖。 其中有些點是黑點,其他點是白點。 現在每個白點都要與他距離最近的黑點通過最短路連線(如果有很多個黑點,可以選取其中
【JZOJ3973】【NOI2015模擬1.10】【NOI2013湖南省隊集訓】黑白樹(wbtree)(並查集)
Problem 給定一棵樹,邊的顏色為黑或白,初始時全部為白色。維護兩個操作: 1. 查詢u到根路徑上的第一條黑色邊的標號。 2. 將u到v路徑上的所有邊的顏色設為黑色。 Hint 對於30%的資料:n,m≤103n,m≤103 對於
jzoj5986. 【WC2019模擬2019.1.4】立體幾何題 (權值線段樹)
傳送門 題面 題解 不難看出每個點的大小為行列限制中較小的那一個(因為資料保證有解) 對於行的每個限制,能取到的個數是列裡限制大於等於它的數的個數,同理,對於列是行裡大於它的個數(這裡沒有等於,為了避免重複計算) 於是可以對於行列分別開權值線段樹,修改的時候只要把對應的貢獻改一下就好了 //mi
【BZOJ2683】簡單題 [分治][樹狀數組]
math 所有 操作數 def 正整數 || lap ref 維護 簡單題 Time Limit: 50 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description 你有一個N*N的棋盤,每
【bzoj3687】簡單題
#3687. 簡單題 記憶體限制:512 MiB 時間限制:10 Sec 提交 提交記錄 討論 題目描述 小呆開始研究集合論了,他提出了關
JZOJ5612. 【NOI2018模擬3.29】第3題
題意: 資料範圍: Analysis: 20分很顯然的設 f i
JZOJ 5878. 【NOIP2018提高組模擬9.22】電路圖 A
Description nodgd 要畫一個電路圖。 這是一個很簡單的電路圖,所有的元件都是串聯關係,從整體來看就是一個環狀的結構。畫電路圖有很多要求,nodgd 為了畫得好看就又添加了一些 額外的要求。所有要求歸結起來有以下幾點: 1、這個環狀電路上有n個雙端
JZOJ-senior-5878. 【NOIP2018提高組模擬9.22】電路圖 A
Time Limits: 1000 ms Memory Limits: 262144 KB Description nodgd 要畫一個電路圖。 這是一個很簡單的電路圖,所有的元件都是串聯關係,從整體
【BZOJ 3687】簡單題
題目描述 小呆開始研究集合論了,他提出了關於一個數集四個問題: 1.子集的異或和的算術和。 2.子集的異或和的異或和。 3.子集的算術和的算術和。 4.子集的算術和的異或和。 目前為止,小呆已經解決了前
【LG4148】簡單題
【LG4148】簡單題 題面 洛谷 題解 \(kdt\)模板題呀。。。 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <
【樹狀陣列】【CQOI2006】簡單題
【題目描述】 有一個n個元素的陣列,每個元素初始均為0。有m條指令,要麼讓其中一段連續序列數字反轉——0變1,1變0(操作1),要麼詢問某個元素的值(操作2)。例如當n=20時,10條指令如下: 【輸入格式】 第一行包含兩個整數n,m
【凸優化】【長鏈剖分】【2019冬令營模擬1.8】tree
PROMBLEM 給你一棵樹,你需要在樹上選擇恰好 m條點不相交的、長度至少為 k的路徑,使得路徑所覆蓋的點權和儘可能大。求最大點權和。 資料保證有解。 SOLUTION 這是一道綜合的題目,考察凸優化、長鏈剖分、樹形DP、以及關於陣列空間的優化 首先引進凸優