NOIP 提高組 2016 組合數問題
阿新 • • 發佈:2020-08-28
肝了億天的程式碼(我太蒻了QWQ)
洛谷大大P2822(https://www.luogu.com.cn/problem/P2822)
題目描述
組合數表示的是從n個物品中選出m個物品的方案數。舉個例子,從(1,2,3)三個物品中選擇兩個物品可以有(1,2),(1,3),(2,3)這三種選擇方法。根據組合數的定義,我們可以給出計算組合數的一般公式:
組合數(n,m)= n!
m!(n-m)!特別地,定義0!=1。
小蔥想知道如果給定n,m和k對於所有的0≤i≤n,0≤j≤min(i,m)有多少對(i,j)滿足k|組合數(i,j)。
簡單來說,給定n,m,k,求出使k整除組合數(i,j)的i,j的對數。
程式實現分為三部分,預處理,讀入和判斷輸出。
核心思想是將k分解質因數(小於20即可),然後列舉i和j,利用字首和進行判斷。
額。。。
還是上程式碼吧。。。
(本人碼風 驚 奇 ,見諒 [ 抱拳 ] )
#include<bits/stdc++.h>
using namespace std;
int t,k,f[2001][10],F[2001][10],d[10],p[10],v[10]={0,2,3,5,7,11,13,17,19,0},g[2002][2002];//v陣列儲存判斷所需質數
void fi(int a){//fi函式用於預處理分解小於2000的數
for(int i=1;i<=8;i++){
int r=a;
while(r%v[i]==0){
f[a][i]++;//f陣列儲存1~2000每個數每個質因子的個數
r/=v[i];
}
}
return ;
}
void c(int x,int y){//c函式用於求出指定i和j的每個質因子的個數
for(int i=1;i<=8;i++){
p[i]=F[x][i]-F[y][i]-F[x-y][i];//p陣列儲存指定i和j的每個質因子個數,根據公式,n-m-(n-m)即為組合數質因子
}
return ;
}
int pd(){//pd函式用於判斷是否被k整除
for(int i=1;i<=8;i++){
if(d[i]>p[i]){
return 0;
}
}
return 1;
}
int main(){
cin>>t>>k;
for(int i=1;i<=2000;i++){//預處理
fi(i);
}
for(int i=1;i<=2000;i++){
for(int j=1;j<=8;j++){
F[i][j]=F[i-1][j]+f[i][j];//F陣列儲存1~2000各個字首和
}
}
for(int i=1;i<=8;i++){//對k進行分解
int r=k;
while(r%v[i]==0){
d[i]++;
r/=v[i];
}
}
int n,m;
for(int i=0;i<=2000;i++){//預處理列舉i和j(不用最後重複列舉)
for(int j=0;j<=min(i,2000);j++){
memset(p,0,sizeof(p));
c(i,j);
if(j>=1){
g[i][j]=g[i][j-1]+pd();//g陣列儲存指定i和最大的j的符合數量
}
}
}
while(t--){
cin>>n>>m;
int h=0;
for(int i=0;i<=n;i++){
h+=g[i][min(i,m)];//求和計算
}
cout<<h<<endl;
}
return 0;
}