中國石油大學ACM俱樂部開放訓練賽


問題 A: sciorz畫畫

題目描述

眾所周知,sciorz會畫畫。某天,sciorz畫了一個凸多邊形,這個多邊形的每個頂點都有一個權值a[i]。sciorz覺得這個凸多邊形不夠美麗,於是他決定在n個點之間連線,最終用n-3條不相交的線將這個凸n邊形分割成n-2個三角形。sciorz認為,一個三角形的美麗值是三個頂點權值的乘積,凸多邊形的美麗值是其內部三角形的美麗值的和。sciorz想找到一種分割方案,使得這個凸多邊形的美麗值最大。sciorz忙着刷難題,所以他隨手就把這個簽到題扔給你,希望你幫sciorz算出最大的美麗值。

輸入

第一行一個t,表示有t組樣例。
每組樣例的第一行是一個n,表示多邊形的邊數。
第二行n個數,第i個數表示多邊形第i個頂點的權值a[i],按逆時針順序給出。

輸出

對於每組樣例,輸出一行。格式為"Case #x: y",x為樣例編號,y為答案。

樣例輸入 Copy

2
3
1 2 3 
4
1 2 3 4

樣例輸出 Copy

Case #1: 6
Case #2: 32

提示

第一個樣例只有一個三角形,所以不用分割,答案是1*2*3=6。
第二個三角形,最優分割方案是分割為1 2 4和2 3 4兩個三角形,答案是1*2*4+2*3*4=32

1<=t<=100
3<=n<=100
1<=a[i]<=100
 
一開始忘了輸出格式,莫名wa了兩發,剁手
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
int n;
ll a[1000];
ll dp[1000][1000];
int ca=1;
void solve() {
    memset(a,0,sizeof 0);
    memset(dp,0,sizeof(dp));
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
        scanf("%lld",&a[i]);
    for(int i=n; i>=1; i--) {
        for(int j=i+1; j<=n; j++) {
            if(j-i==1)
                dp[i][j]=0;
            else if(j-i==2)
                dp[i][j]=a[i]*a[i+1]*a[i+2];
            else
                for(int k=i+1; k<=j-1; k++) {
                    dp[i][j]=max(dp[i][j],(dp[i][k]+dp[k][j]+a[i]*a[j]*a[k]));
                }
        }
    }
    printf("Case #%d: ",ca++);
    printf("%lld\n",dp[1][n]);
}
int main() {
    int t;
    cin>>t;
    while(t--)
        solve();
    return 0;
}

問題 B: 奎奎發紅包

題目描述

情人節又到了,又到了一年一度發紅包的時間。經大家研究決定,今年讓奎奎自願發紅包。
俱樂部有n個人(0<n<100000),每個人都有一個單身值v[i]與親密度t[i](0≤v[i]≤10000,0≤t[i]≤10000),單身值越大的人,在情人節的時候就越羡慕奎奎,奎奎就需要給他更大的紅包來安慰他。 由於一個寒假沒有見到奎奎,領紅包的時候大家都想跟奎奎py,花費時間t[i],先py后給紅包噢。
大家都厭倦了等待,如果一個人等了時間t,那么奎奎發給他的紅包大小就是v[i]·t。
但是奎奎還要和女朋友去快樂,想要花最少的錢來滿足大家。
請你幫他計算最少需要發多少錢的紅包。

輸入

第一行一個整數n。接下來n行,每行兩個數v[i]和t[i]。

輸出

一個整數表示答案。

樣例輸入 Copy

4
1 4
2 3
3 2
4 1

樣例輸出 Copy

35

//直接貪心
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std ;
const int N=100010;
typedef long long ll;
int f[N];
struct S {
    int v,t;
} st[N];
bool cmp(S a,S b) {
    return a.t*b.v<a.v*b.t;
}
int main() {
    int t=1;
    for(int c=1; c<=t; c++) {
        int n;
        cin>>n;
        for(int i=0; i<n; i++) {
            int s,e;
            cin>>s>>e;
            st[i]= {s,e};
        }
        sort(st,st+n,cmp);
        ll ans=0;
        ll sum=0;
        for(int i=0; i<n; i++) {
            ans+=st[i].t;
            sum+=st[i].v*ans;
        }
        cout<<sum<<endl;
    }
}

問題 C: 關於我轉生變成史萊姆這檔事

題目描述

關於我轉生變成史萊姆這檔事這部番劇中,上班族的三上悟因為某個事件而作為史萊姆在異世界轉生了。在轉生時得到了“大賢者”和“捕食者”這兩個獨特技能。雖然身為史萊姆,但也想和其他種族建立起友好關系。魔素是異世界里面魔物含有的魔力精華,捕食者這個技能就是吞噬魔素,捕食者的技能要求非常苛刻,如果你第一天吞噬了b魔素,那么你第二天可以吞噬第一天的2~9倍(必須是其中一個整數),也就是2b~9b,也就是說,史萊姆在第i天所吞噬的魔素一定是第i-1天的2~9倍,而且還必須是它的整數倍。
作為史萊姆手下的得力助手,哥布林們准備了大量的魔物供主人食用,現在史萊姆已經知道了這些魔物含有S魔素,現在請大賢者合理安排第一天要吞噬和接下來每天需要增加的魔素倍數,好讓史萊姆能在最短的天數內恰好吞噬完魔素。由於大賢者要研究“哲學”,無暇顧及這些小事,現在只能請你幫忙,但是大賢者還建議,這些魔素至少要用兩天來吞噬。
 

輸入

一個正整數S,代表要吞噬的魔素總量。

輸出

一個數,代表要吞噬的天數,如果無解輸出-1。

樣例輸入 Copy

571

樣例輸出 Copy

5

提示

對於30%數據,有S<=100;
對於70%數據,有S<=107;
對於100%數據,有9<S<=8×108
 
玄學

 

每一步都要整除,a1表示第一天的量 剩下的表示倍數,能過也是玄學

 

#include<iostream>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f ;
int read()
{
    int res=0,ch,flag=0;
    if((ch=getchar())=='-')             //判斷正負
        flag=1;
    else if(ch>='0'&&ch<='9')           //得到完整的數
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;
}
ll ans=INF;
ll calc(ll n)
{
    if(n<2)return INF;
    if(2<=n&&n<=9)return 1;
    ll res=INF;
    for(ll i=2;i<=9;++i)
        if(n%i==0)
        res=min(res,calc(n/i-1)+1);
    return res;
}
int main()
{
    ll n=read();
    for(ll i=1;i*i<=n;++i)
        //枚舉因數,也就是第一次取多少 
        if(n%i==0)
        {
            ans=min(ans,calc(n/i-1)+1);
            //對兩個因數遞歸 
            if(i!=1)
                ans=min(ans,calc(i-1)+1);
        }
    if(ans==INF)
        puts("-1");
    else 
        cout<<ans;
    return 0;
}

 

 

問題 D: 大數

題目描述

小七是一個很可愛很努力的女孩子。她對大數的運算非常感興趣,在學習了幾天之后,終於精通了大數的加減乘除。但是自從她學會了 JAVA ,她覺得大數實在是太簡單太無聊了,因為運用 JAVA 中 BigInteger 大整數類,可以輕松實現大數的加減乘除。某一天她突然發現,很多大數的題目的數據都有規律。這些數都是由比他小的某個數重復構成,比如說 121212 由 12重復構成 ,233233 ,由233重復構成,而1231231並不是由123重復構成。無聊的小七終於找到了樂子,她想要找到每個大數是由哪個比它小的數重復構成。算法剛入⻔的小七無法解決這個問題,於是她求助於你。
 

輸入

一行 一個正整數n(n<=101000000)。

輸出

一行
如果存在多種,輸出最小的滿足題意的數;
如果不存在,則輸出-1.
 

樣例輸入 Copy

121212

樣例輸出 Copy

12

KMP求循環節
#include <bits/stdc++.h>

#define rep(i, l, r) for (int i = l; i <= r; ++ i)

using namespace std;

const int MaxN = 1e7 + 10;

int n;
char s1[MaxN];
int p[MaxN];

int main() {
    scanf("%s", s1 + 1);
    n = strlen(s1 + 1);
    if (n == 0) return 0;
    int j = 0;
    rep (i, 1, (n - 1)) {
        while (j > 0 && s1[j + 1] != s1[i + 1])
            j = p[j];
        if (s1[j + 1] == s1[i + 1])
            j ++;
        p[i + 1] = j;
    }
    if (n % (n - p[n]) != 0 || n == (n - p[n])) printf("-1");
    else rep (i, 1, n - p[n]) cout << s1[i];
    return 0;
}

 

問題 E: Ktree

題目描述

煉金術師靈岩在與巫師Slanely爭奪餡餅的過程中處於劣勢,於是靈岩召喚出了K樹一起爭奪餡餅。K樹是一棵權值和為s但權值分配方式未定的樹。Slanely偷偷施展法術,使K樹的直徑盡可能小。現在靈岩想知道召喚出的K樹直徑為多少。

輸入

第一行給出兩個整數n和s ,n,s<= 100000, n為節點數, s為樹的總長度。
接下來,每行兩個整數u,v,表示節點u和v之間有一條邊相連。
 

輸出

輸出L,保留兩位小數。

樣例輸入 Copy

6 4
1 2
1 3
1 4
4 5
4 6

樣例輸出 Copy

2.00
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MAXN 1000011
ll deg[MAXN];
int main() {
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    ll n;
    double s;
    cin>>n>>s;
    //要分給每個葉子
    //每個葉子的貢獻(經過他的路徑數量)不會比其父親多 
    for(ll i=1; i<n; ++i) {
        ll u,v;
        cin>>u>>v;
        ++deg[u],++deg[v];
    }
    ll cnt=0;
    //找葉節點 
    for(ll i=1; i<=n; ++i)
        if(deg[i]==1)
            ++cnt;
    printf("%.2lf",s*2.0/cnt);
    return 0;
}

 

 

問題 F: 求和

題目描述

等比數列是指從第二項起,每一項與它的前一項的比值等於同一個常數的一種數列。對於一個等比數列an=a1qn-1,它的前n項的和Sn=a1(1-qn)/(1-q)(q≠1)。現在已知A為n*n的矩陣,S=A+$A^2$+$A^3$+...+$A^m$,你能否正確求出S,並且輸出S中的每一個元素對1000000007取模后的值。

輸入

輸入包括n+1行,第一行包括兩個正整數n, m,分別代表矩陣A的大小和S中的項數,其中1≤n≤30, 1≤m≤109。接下來n行,每行n個元素,相應地代表A中的元素x,其中0≤x≤106。

輸出

輸出包括n行,每行n個元素,相應地代表S中的每一個元素對1000000007取模后的值。

樣例輸入 Copy

1 2019
1

樣例輸出 Copy

2019

矩陣乘法+快速冪

 

#include <iostream>
#include <cstring>
using namespace std;
struct matrix {
    int data[35][35];
};
int n = 0;
int m = 0;
int k = 0;
//矩陣乘法
matrix mul(matrix a, matrix b) {
    matrix c;
    memset(c.data, 0, sizeof(c.data));
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            for (int k = 1; k <= n; k++) {
                c.data[i][j] = (c.data[i][j] + 1ll * a.data[i][k] * b.data[k][j]) % m;
            }
        }
    }
    return c;
}
//矩陣加法
matrix add(matrix a, matrix b) {
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            a.data[i][j] = (a.data[i][j] + b.data[i][j])%m;
        }
    }
    return a;
}
//矩陣快速冪
matrix quickpow(matrix a, int k) {
    matrix  c;
    memset(c.data, 0, sizeof(c.data));
    for (int i = 1; i <= n; i++)
        c.data[i][i] = 1;
    while (k) {
        if (k & 1) c = mul(c, a);
        k >>= 1;
        a = mul(a, a);
    }
    return c;
}
//正式計算 sum k
matrix sum(matrix a, int k) {
    if (k == 1) return a;
    matrix c;
    memset(c.data, 0, sizeof(c.data));
    for (int i = 1; i <= n; i++)
        c.data[i][i] = 1;
    c = add(c, quickpow(a, k >> 1));
    c = mul(c, sum(a, k >> 1));
    if (k & 1) c = add(c, quickpow(a, k));
    return c;
}
int main() {
    matrix mat;
    cin >> n;
    cin >> k;
    m=1000000007;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> mat.data[i][j];
        }
    }
    matrix ret = sum(mat, k);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cout << ret.data[i][j] << " ";
        }
        cout << endl;
    }
    return 0;
}

 

問題 G: 奎奎畫畫

題目描述

“為你寫詩,為你靜止,為你做不可能的事”,愛情是一種怪事,它讓奎奎開始學習畫畫。奎奎認為一張畫的藝術價值等於畫上的白色聯通塊個數(當一個格子和它上下左右四個方向上的某個相鄰格子顏色相同,則認為它們屬於同一個聯通塊),奎奎還認為他作畫的藝術價值和妹子對他的好感度緊密相關,因此奎奎非常在意每一時刻他的畫的藝術價值。 為了簡化題目,奎奎在一張n行m列的白色矩形格子畫布上作畫,他一共畫了q筆,每一筆都是從(x1,y1)格子開始到(x2,y2)格子結束(x1=x2或y1=y2),將所有滿足x1<=x<=x2並且y1<=y<=y2的格子塗黑。奎奎想知道當他畫完每一筆之后,這幅畫的藝術價值是多少。

輸入

第一行三個整數n,m,q (1≤n, m≤1000, 1≤q≤10000 )
下面q行每行4個整數x1,y1,x2,y2 (1≤x1≤x2≤n, 1≤y1≤y2≤m)描述奎奎畫的q條線段的起點和終點
 

輸出

q行,對於奎奎畫的每一條線段,輸出一行一個整數表示該線段畫完之后畫布上白色聯通塊的個數。

樣例輸入 Copy

4 6 5
2 2 2 6
1 3 4 3
2 5 3 5
4 6 4 6
1 6 4 6

樣例輸出 Copy

1
3
3
4
3
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MAXN 1011
int read() {
    int res=0,ch,flag=0;
    if((ch=getchar())=='-')             //判斷正負
        flag=1;
    else if(ch>='0'&&ch<='9')           //得到完整的數
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;
}
ll fa[MAXN*MAXN];
ll find(ll x) {
    if(fa[x]==x)return x;
    return fa[x]=find(fa[x]);
}
bool uni(ll u,ll v) {
    u=find(u),v=find(v);
    if(u==v)
        return 0;
    fa[u]=v;
    return 1;
}
struct opt {
    ll x1,y1,x2,y2;
} a[MAXN*10];
ll c[MAXN][MAXN],ans=0;
const ll mx[]= {0,1,0,-1},my[]= {1,0,-1,0};
ll n,m,Q;
void ctrb(ll x,ll y) {
    for(ll i=0; i<4; ++i) {
        ll vx=x+mx[i],vy=y+my[i];
        //如果在一個並查集里面,就不用減去
        //如果不在的話,說明相鄰的有白塊,直接合並,減去下面多加的次數 
        if(vx>0&&vx<=n&&vy>0&&vy<=m&&!c[vx][vy])
            ans-=uni((x-1)*m+y,(vx-1)*m+vy);
    }
}
ll p[MAXN*10];
int main() {
    //從Q~1處理每個詢問
    //離線的時候順便用二維差分算一下覆蓋次數
    //然后對於每個出現次數為0的點,都和相鄰點合並(如果相鄰點沒被覆蓋)
    //順便統計連通塊數量
    //然后倒着,把覆蓋次數減掉
    //新的出現次數為0的點也合並一下就好了 
    n=read(),m=read(),Q=read();
    for(ll i=1; i<=Q; ++i) {
        ll x1=read(),y1=read(),x2=read(),y2=read();
        //二維差分處理 
        ++c[x1][y1],--c[x2+1][y1],--c[x1][y2+1],++c[x2+1][y2+1];
        a[i]=opt {x1,y1,x2,y2};
    }
    //二位差分處理 
    for(ll i=1; i<=n; ++i)
        for(ll j=1; j<=m; ++j) {
            c[i][j]+=c[i-1][j]+c[i][j-1]-c[i-1][j-1];
            //並查集維護 
            fa[(i-1)*m+j]=(i-1)*m+j;
        }
    //如果是0,那么就說明還沒有被覆蓋過, 統計連通塊的數量 
    for(ll i=1; i<=n; ++i)
        for(ll j=1; j<=m; ++j)
            if(!c[i][j])
                ++ans,ctrb(i,j);
    for(ll i=Q; i; --i) {
        p[i]=ans;
        ll x1=a[i].x1,y1=a[i].y1,x2=a[i].x2,y2=a[i].y2;
        //倒着處理,覆蓋次數-- 
        for(ll x=x1; x<=x2; ++x)
            for(ll y=y1; y<=y2; ++y)
                --c[x][y];
        //統計塊數 
        for(ll x=x1; x<=x2; ++x)
            for(ll y=y1; y<=y2; ++y)
                if(!c[x][y])++ans,ctrb(x,y);
    }
    for(ll i=1; i<=Q; ++i)printf("%lld\n",p[i]);
    return 0;
}

 

 

問題 H: qiqi and sciorz

題目描述

一天,qiqi和sciorz很無聊,他們又玩起來更無聊的取石子游戲,游戲規則是這樣的:

有一堆n個石子,qiqi先取,每次最少取一個,第一次取的時候最多取n-1個,之后每次不能超過上一次的k倍,取得最后一個石子的為勝利,也就是說不能操作的為敗.

然而sciorz早已洞穿了一切,他已經知道了誰會勝利,並且他急着去聊妹子,於是他開始催促qiqi快點開始,但是qiqi並不會玩,你能幫幫他嗎?
 

輸入

一行一個整數T表示玩了T局(T<=1000)

之后T行,每行兩個整數n,k.

 

輸出

如果qiqi輸了,輸出一個字符串"qiqi lose"。

如果sciorz輸了,輸出qiqi第一次應該取走多少個。

題目保證不會有第三種結局
 

樣例輸入 Copy

2
2 1000
3 1

樣例輸出 Copy

qiqi lose
1

提示

第一個樣例,qiqi 第一步只能取走1個石子,然后sciorz取走最后一個,qiqi 輸了。
第二個樣例,qiqi 第一步取走1個石子,然后sciorz取走一個,qiqi取走最后一個,qiqi獲得了勝利
對於25%的數據有n<=10,k<=10
對於另外25%的數據有n<=10
對於另外25%的數據有k<=10
對於100%的數據有n<=100000,k<=100000
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
    int res=0,ch,flag=0;
    if((ch=getchar())=='-')             //判斷正負
        flag=1;
    else if(ch>='0'&&ch<='9')           //得到完整的數
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;
}
#define MAXN 100011
ll f[MAXN],t[MAXN];
int main()
{
    ll task=read();
    while(task--)
    {
        ll n=read(),k=read();
        f[1]=t[1]=1;
        ll len=1,it=1;
        while(n>f[len])
        {
            ++len;
            f[len]=t[len-1]+1;
            while(f[it+1]*k<f[len])++it;
            if(f[it]*k<f[len])t[len]=t[it]+f[len];
            else t[len]=f[len];
        }
        if(n==f[len])
        {
            puts("qiqi lose");continue;
        }
        while(n)
        {
            if(n>=f[len])
            {
                n-=f[len];
                if(!n)
                {
                    printf("%lld\n",f[len]);
                    break;
                }
            }
            --len;
        }
    }
    return 0;
}

問題 I: 星區划分

題目描述

愛好天文的小七發明了一種太空分區方法,在這個方法中,宇宙里亮度相近的星星被划為同一個星區。空間中任意相鄰或坐標相同的星星若亮度差不大於給定整數M,則這兩個星星屬於同一星區(兩個星星可能會有相同的坐標)。

現給你一個空間n個星星的三維坐標(x,y,z),和亮度值v,每個星星的上、下、左、右、前、后的六個相鄰位置被認為是與其相鄰的。請你計算一下該空間內的星區數量。
 

輸入

第一行1個正整數n。n<=1000  
第二行 1個正整數m。m<=109  
第二行到第n+1行,每行四個正整數x,y,z,v。0<=x,y,z,v<=109 

輸出

一行正整數k,代表星區數量。
 

樣例輸入 Copy

5   
2  
1 1 1 2  
1 2 3 2  
1 2 2 5  
1 1 0 3  
1 0 1 3

樣例輸出 Copy

3

#include<iostream>
#include<cmath>
using namespace std;
#define rep_1(i,m,n) for(int i=m;i<=n;i++)
#define mem(st) memset(st,0,sizeof st)
int read() {
    int res=0,ch,flag=0;
    if((ch=getchar())=='-')             //判斷正負
        flag=1;
    else if(ch>='0'&&ch<='9')           //得到完整的數
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;
}
typedef long long ll;
typedef unsigned long long ull;
const int inf = 0x3f3f3f3f;  //int無窮大值1061109567

const int N=101010;
struct node {
    ll x,y,z,w;
} e[N];
ll fa[N];
ll n,m;
bool check(node a,node b) {
    if(abs(a.w-b.w)>m)
        return false;
    return abs(a.x-b.x)+abs(a.y-b.y)+abs(a.z-b.z)<=1;
}
ll find(ll x) {
    if(fa[x]==x)
        return x;
    return fa[x]=find(fa[x]);
}
void uni(ll u,ll v) {
    u=find(u);
    v=find(v);
    fa[u]=v;
}
int main() {
    cin>>n>>m;
    for(ll i=1; i<=n; i++)
        cin>>e[i].x>>e[i].y>>e[i].z>>e[i].w;
    for(ll i=1; i<=n; i++)
        fa[i]=i;
    for(ll i=1; i<=n; i++)
        for(ll j=1; j<=n; j++)
            if(check(e[i],e[j]))
                uni(i,j);
    ll ans=0;
    for(ll i=1; i<=n; i++)
        if(find(i)==i)
            ans++;
    cout<<ans<<endl;
    return 0;
}

問題 J: 加油2020

題目描述

由於Slanely的隊友們都不會數論,Slanely研究數學研究得頭都快禿了。
Slanely最近在研究狄利克雷卷積,狄利克雷卷積是指:設f(x)是一個數論函數,g(x)也是一個數論函數,則h(n)也是一個數論函數,其定義為 。Slanely看到這個定義就感覺頭皮發麻,於是就准備出一道相關的題來難為新生。設f(x)為x的因子數,g(x)為x的因子和,求其狄利克雷卷積,即 。尷尬的是,Slanely發現他並不會做這道他出的題,於是他只能修改了題目。修改后的題目如下:

設f(x)為x的因子數,g(x)為x的因子和,求  。由於答案很大,你需要對結果取模p。
 

輸入

一行,兩個整數,分別表示n和p, n<=1000,p<1000000000000000000,保證p是一個質數,且p>=673。。

輸出

輸出 對p求模的結果

樣例輸入 Copy

242 1000000007

樣例輸出 Copy

349885024


問題 K: 數學問題

題目描述

我們高中曾經學過何為組合數。 那么,給出整數n,m,g,聰明的你能否求出有多少整數對(i,j),滿足g整除 嗎?(其中0≤i≤n,0≤j≤min(i,m))。 (提示:n!=1×2×⋯×n;特別地,0!=1。)

輸入

第一行一個整數T(T<=104 ),表示測試數據的組數;
第二行一個整數g(1<g<=25);
接下來T行每行兩個整數n,m(n,m<=2000);
n,m,g的意義見題目描述。
 

輸出

輸出T行,每行一個整數,表示有多少對整數對(i,j)滿足g整除 (0≤i≤n,0≤j≤min(i,m))。
 
noip原題
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int t,k,n,m;
int c[2005][2005],s[2005][2005];
void prepare();
int main() {
    memset(c,0,sizeof(c));
    memset(s,0,sizeof(s));
    cin>>t>>k;
    prepare();
    while(t--) {
        cin>>n>>m;
        if(m>n) m=n;
        cout<<s[n][m]<<endl;
    }
    return 0;
}
void prepare() {
    c[1][1]=1;
    for(int i=0; i<=2000; i++) c[i][0]=1;
    for(int i=2; i<=2000; i++) {
        for(int j=1; j<=i; j++) {
            c[i][j]=(c[i-1][j]+c[i-1][j-1])%k;
        }
    }
    for(int i=2; i<=2000; i++) {
        for(int j=1; j<=i; j++) {
            s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
            if(c[i][j]==0) s[i][j]+=1;
        }
        s[i][i+1]=s[i][i];
    }
}

 

問題 L: 迪雜斯特

題目描述

在A國,一年有50!=1×2×...×50天,每天的編號從1到50!。
A國的土地上經常發生自然災害。據A國科學家的妍究,A國有n種自然災害,每種自然災害的發生都有周期性。
具體地,第i種自然災害可以用一個只包含Y和N組成的字符串組成。
設這個字符串的長度為L。如果這個字符串的第j個字符為Y,那么這就表示對於所有的k∈N,在第k×L+j天會發生第i種自然災害,否則不會發生。
一天同時發生的自然災害種數決定了該天整個A國境內的危險程度。
所以,你需要對於所有的0≤i≤n,求出一年內有多少天同時發生的自然災害種數恰好為i。

輸入

第一行一個正整數n。
接下來n行,每行一個Y和N組成的字符串,描述一種自然災害。

輸出

輸出n+1行,其中第i行表示一年內,同時發生的自然災害種數恰好為i的天數對10007取模后的結果。

樣例輸入 Copy

【樣例1】
2
YNN
NYNN
【樣例2】
4
NYYYYNNYYYYNNNNNYYNNNYYNNYNNNNNYNYYYNNYNYNYYNNYYYN
NYYYYNYNNNYNNNYNYNYNYYY
YNNNYNNNYYNYNYNNYNYYYNNN
YYNNNNYYYYNYYNYNYYNYNNYYYNNNYYNNYYNYN

樣例輸出 Copy

【樣例1】
6621
514
6107
【樣例2】
3595
3506
5771
9830
547

提示

對於10%的數據n=2;
對於20%的數據所有字符串長度的乘積不超過1111111;
另有20%的數據所有字符串長度兩兩互質或相等;
另有30%的數據所有字符串長度不超過48;
對於100%的數據,所有字符串長度不超過50,n≤30。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM