【NOIP 2016 day2 T1 T2】組合數問題,蚯蚓——題解

組合數問題

題目描述

組合數Cmn

​表示的是從n個物品中選出m個物品的方案數。舉個例子,從(1,2,3) 三個物品中選擇兩個物品可以有(1,2),(1,3),(2,3)這三種選擇方法。根據組合數的定 義,我們可以給出計算組合數的一般公式:

Cmn=n!m!(nm)!

其中n! = 1 × 2 × · · · × n

小蔥想知道如果給定n,m和k,對於所有的0<=i<=n0<=j<=min(i,m) 有多少對 (i,j)滿足Cji
是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;
}

蚯蚓

題目描述

本題中,我們將用符號c 表示對c向下取整,例如:3.0=3.1=3.9

蛐蛐國最近蚯蚓成災了!隔壁跳蚤國的跳蚤也拿蚯蚓們沒辦法,蛐蛐國王只好去請神刀手來幫他們消滅蚯蚓。

蛐蛐國裏現在共有n只蚯蚓(n爲正整數)。每隻蚯蚓擁有長度,我們設第i只蚯蚓的長度爲
ai(i=1,2,...,n) ,並保證所有的長度都是非負整數(即:可能存在長度爲0的蚯蚓)。

每一秒,神刀手會在所有的蚯蚓中,準確地找到最長的那一隻(如有多個則任選一個)將其切成兩半。神刀手切開蚯蚓的位置由常數p(是滿足0<p<1 的有理數)決定,設這隻蚯蚓長度爲x,神刀手會將其切成兩隻長度分別爲pxxpx 的蚯蚓。特殊地,如果這兩個數的其中一個等於0,則這個長度爲0的蚯蚓也會被保留。此外,除了剛剛產生的兩隻新蚯蚓,其餘蚯蚓的長度都會增加q(是一個非負整常數)。

蛐蛐國王知道這樣不是長久之計,因爲蚯蚓不僅會越來越多,還會越來越長。蛐蛐國王決定求助於一位有着洪荒之力的神祕人物,但是救兵還需要m秒才能到來……

(m爲非負整數)

蛐蛐國王希望知道這m秒內的戰況。具體來說,他希望知道:

•m秒內,每一秒被切斷的蚯蚓被切斷前的長度(有m個數)

•m秒後,所有蚯蚓的長度(有n+m個數)。

蛐蛐國王當然知道怎麼做啦!但是他想考考你……

輸入輸出格式

輸入格式:
第一行包含六個整數n,m,q,u,v,t,其中:n,m,q的意義見【問題描述】;u,v,t均爲正整數;你需要自己計算p=u/v (保證0<u<v )t是輸出參數,其含義將會在【輸出格式】中解釋。

第二行包含n個非負整數,爲ai,a2,...,an ,即初始時n只蚯蚓的長度。

同一行中相鄰的兩個數之間,恰好用一個空格隔開。

保證
1n1050<m71060u<v1090q2001t710<ai108

輸出格式:
第一行輸出m/t 個整數,按時間順序,依次輸出第t秒,第2t秒,第3t秒……被切斷蚯蚓(在被切斷前)的長度。

第二行輸出(n+m)/t 個整數,輸出m秒後蚯蚓的長度;需要按從大到小的順序,依次輸出排名第t,第2t,第3t……的長度。

同一行中相鄰的兩個數之間,恰好用一個空格隔開。即使某一行沒有任何數需要 輸出,你也應輸出一個空行。

請閱讀樣例來更好地理解這個格式。

輸入輸出樣例

輸入樣例#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章