組合數問題
題目描述
組合數
表示的是從n個物品中選出m個物品的方案數。舉個例子,從(1,2,3) 三個物品中選擇兩個物品可以有(1,2),(1,3),(2,3)這三種選擇方法。根據組合數的定 義,我們可以給出計算組合數的一般公式:
其中n! = 1 × 2 × · · · × n
小蔥想知道如果給定n,m和k,對於所有的
是k的倍數。
輸入輸出格式
輸入格式:
第一行有兩個整數t,k,其中t代表該測試點總共有多少組測試數據,k的意義見 【問題描述】。
接下來t行每行兩個整數n,m,其中n,m的意義見【問題描述】。
輸出格式:
t行,每行一個整數代表答案。
輸入輸出樣例
輸入樣例#1:
1 2
3 3
輸出樣例#1:
1
輸入樣例#2:
2 5
4 5
6 7
輸出樣例#2:
0
7
——————————————————————
作爲day2T1題,我覺得也不是純送分的了。
我們有組合數的遞推公式,邊算邊取模。
然後用容斥原理做二維前綴和(自己瞎起的名字),預處理即可。
思路清晰,但是作爲T1突然間不是暴力就會很蒙吧。
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
ll f[2001][2001];
ll sum[2001][2001];
int main(){
int t,k;
scanf("%d%d",&t,&k);
for(int i=0;i<=2000;i++){
f[i][i]=1;
f[i][0]=1;
}
for(int i=1;i<=2000;i++){
for(int j=1;j<i;j++){
f[i][j]=f[i-1][j]+f[i-1][j-1];
f[i][j]%=k;
}
}
for(int i=1;i<=2000;i++){
for(int j=1;j<=2000;j++){
if(!f[i][j]&&j<=i){
sum[i][j]++;
}
sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
}
}
while(t--){
int n,m;
scanf("%d%d",&n,&m);
printf("%lld\n",sum[n][m]);
}
return 0;
}
蚯蚓
題目描述
本題中,我們將用符號
蛐蛐國最近蚯蚓成災了!隔壁跳蚤國的跳蚤也拿蚯蚓們沒辦法,蛐蛐國王只好去請神刀手來幫他們消滅蚯蚓。
蛐蛐國裏現在共有n只蚯蚓(n爲正整數)。每隻蚯蚓擁有長度,我們設第i只蚯蚓的長度爲
每一秒,神刀手會在所有的蚯蚓中,準確地找到最長的那一隻(如有多個則任選一個)將其切成兩半。神刀手切開蚯蚓的位置由常數p(是滿足
蛐蛐國王知道這樣不是長久之計,因爲蚯蚓不僅會越來越多,還會越來越長。蛐蛐國王決定求助於一位有着洪荒之力的神祕人物,但是救兵還需要m秒才能到來……
(m爲非負整數)
蛐蛐國王希望知道這m秒內的戰況。具體來說,他希望知道:
•m秒內,每一秒被切斷的蚯蚓被切斷前的長度(有m個數)
•m秒後,所有蚯蚓的長度(有n+m個數)。
蛐蛐國王當然知道怎麼做啦!但是他想考考你……
輸入輸出格式
輸入格式:
第一行包含六個整數n,m,q,u,v,t,其中:n,m,q的意義見【問題描述】;u,v,t均爲正整數;你需要自己計算
第二行包含n個非負整數,爲
同一行中相鄰的兩個數之間,恰好用一個空格隔開。
保證
輸出格式:
第一行輸出
第二行輸出
同一行中相鄰的兩個數之間,恰好用一個空格隔開。即使某一行沒有任何數需要 輸出,你也應輸出一個空行。
請閱讀樣例來更好地理解這個格式。
輸入輸出樣例
輸入樣例#1:
3 7 1 1 3 1
3 3 2
輸出樣例#1:
3 4 4 4 5 5 6
6 6 6 5 5 4 4 3 2 2
輸入樣例#2:
3 7 1 1 3 2
3 3 2
輸出樣例#2:
4 4 5
6 5 4 3 2
輸入樣例#3:
3 7 1 1 3 9
3 3 2
輸出樣例#3:
//空行
2
————————————————————
做這題的時候想的是T2應該不至於很難……
wdm看了正解都不是很懂的題,特地mark一下。
c++選手福利,優先隊列35分,優化後85分。
正解就是不用優先隊列(logn誰用誰傻子)
通過口胡證明能夠發現,我們可以將每次切好的蚯蚓,長的放一堆,短的放一堆,則他們長度是有序的。
那麼我們自然就不用優先隊列了,就比較原隊列和長短隊列的front挑一個最長的剪就行了。
但很明顯我們不可以將所有的蚯蚓都減去q。
一個明顯的優化就是對於切的蚯蚓-q即可。
這樣要求我們拿出蚯蚓時+(t-1)*q(不加則會因精度問題產生誤差),然後切完的蚯蚓每個-t*q即可。
最後我們對於每個蚯蚓+t/*q就是原長。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
inline int read(){
int X=0,w=1; char ch=0;
while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
return X*w;
}
int a[100001];
queue<int>q1,q2,q3;
bool cmp(int c,int d){
return c>d;
}
int main(){
int n=read();
int m=read();
int q=read();
int u=read();
int v=read();
int t=read();
double p=(double)u/v;
for(int i=1;i<=n;i++){
a[i]=read();
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++){
q1.push(a[i]);
}
int cnt=0;
while(cnt!=m){
cnt++;
int t1=-2147483647,t2=-2147483647,t3=-2147483647;
if(!q1.empty()){
t1=q1.front();
}
if(!q2.empty()){
t2=q2.front();
}
if(!q3.empty()){
t3=q3.front();
}
t1+=(cnt-1)*q;
t2+=(cnt-1)*q;
t3+=(cnt-1)*q;
if(t1>=t2&&t1>=t3){
if(cnt%t==0){
printf("%d ",t1);
}
int f1=p*t1;
int f2=t1-f1;
f1-=cnt*q;
f2-=cnt*q;
if(f1>f2){
q2.push(f1);
q3.push(f2);
}else{
q3.push(f1);
q2.push(f2);
}
q1.pop();
}else if(t2>=t1&&t2>=t3){
if(cnt%t==0){
printf("%d ",t2);
}
int f1=p*t2;
int f2=t2-f1;
f1-=cnt*q;
f2-=cnt*q;
if(f1>f2){
q2.push(f1);
q3.push(f2);
}else{
q3.push(f1);
q2.push(f2);
}
q2.pop();
}else if(t3>=t1&&t3>=t2){
if(cnt%t==0){
printf("%d ",t3);
}
int f1=p*t3;
int f2=t3-f1;
f1-=cnt*q;
f2-=cnt*q;
if(f1>f2){
q2.push(f1);
q3.push(f2);
}else{
q3.push(f1);
q2.push(f2);
}
q3.pop();
}
}
printf("\n");
int k=0;
while(!q1.empty()||!q2.empty()||!q3.empty()){
k++;
int t1=-2147483647,t2=-2147483647,t3=-2147483647;
if(!q1.empty())t1=q1.front();
if(!q2.empty())t2=q2.front();
if(!q3.empty())t3=q3.front();
t1+=cnt*q;t2+=cnt*q;t3+=cnt*q;
if(t1>=t2&&t1>=t3){
if(k%t==0)printf("%d ",t1);q1.pop();
}else if(t2>=t3&&t2>=t1){
if(k%t==0)printf("%d ",t2);q2.pop();
}else if(t3>=t1&&t3>=t2){
if(k%t==0)printf("%d ",t3);q3.pop();
}
}
return 0;
}