1. 程式人生 > >NOIP2003年普及組題解

NOIP2003年普及組題解

這是第一題:https://www.luogu.org/problemnew/show/P1042
首先,在做題之前要注意兩個地方:
‘E’不一定出現在文字的末尾,也不一定出現在某行的末尾
比賽必須要領先2個球才能獲勝,11:10的比分是不存在的
好了,廢話不多說,直接上程式碼~~~

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxN=100100;
string
s[maxN]; int a[maxN],b[maxN],a2[maxN],b2[maxN]; int n=1,t=1,t2=1; bool check(int x) { int t=s[x].size(); for(int i=0;i<t;i++) if(s[x][i]=='E')return 0; return 1; } int main() { freopen("table.in","r",stdin); freopen("yable.out","w",stdout); cin>>s[n]; while(check(n)){ n++; cin
>>s[n]; } for(int i=1;i<=n;i++){ int lenth=s[i].size(); for(int j=0;j<lenth;j++){ if(s[i][j]=='E'){ for(int i=1;i<=t;i++) cout<<a[i]<<":"<<b[i]<<endl; cout<<endl; for
(int i=1;i<=t2;i++) cout<<a2[i]<<":"<<b2[i]<<endl; return 0; } if(s[i][j]=='W') a[t]++,a2[t2]++; else if(s[i][j]=='L') b[t]++,b2[t2]++; if((a[t]>=11||b[t]>=11)&&abs(a[t]-b[t])>=2) t++; if((a2[t2]>=21||b2[t2]>=21)&&abs(a2[t2]-b2[t2])>=2) t2++; //這裡一定要注意是領先兩分才能贏 } } return 0; }

這裡是第二題:https://www.luogu.org/problemnew/show/P1043
定義 f[0/1][i][j][k]表示左端點在 i,右端點在 j,分成了 k 個部分的最大/最小乘積
最開始做這題開了五層迴圈,內層枚舉了一下斷點和斷點兩側分別分成了多少個部分…
後來(抄題解)發現了其實不用列舉兩側分成了多少個部分,因為這會被之前或之後的迴圈列舉到,打個比方:如果列舉到了左端點是 i,右端點是 j,斷點是 k,左邊分成了p 個部分,右邊分成了 q 個部分。 當然,這裡需要的是五重迴圈,這樣做有超時的風險。
所以,我們只需要考慮最後一組數是從哪個地方開始的就好了
好了,道理講完了,直接暴力上程式碼~~~

#include<iostream>
#include<cstdio>
using namespace std;
const int maxN=0x7fffffff;
int n,m,maxn,minn=maxN;
int qzh[105];
int val[105];
int f[2][105][105][15];

int mod(int x){
    return (x%10+10)%10;
}

void prepare()
{
    for(int i=1;i<=(n<<1);i++)
        qzh[i]=qzh[i-1]+val[i];
    for(int i=1;i<=(n<<1);i++)
        for(int j=i;j<=(n<<1);j++)
            f[0][i][j][1]=f[1][i][j][1]=mod(qzh[j]-qzh[i-1]);
    for(int i=2;i<=m;i++){
        for(int l=1;l<=(n<<1);l++){
            for(int r=l+i-1;r<=l+n-1;r++){
                f[1][l][r][i]=maxN;
                for(int k=l+i-2;k<r;k++){
                    f[0][l][r][i]=max(f[0][l][r][i],f[0][l][k][i-1]*mod(qzh[r]-qzh[k]));
                    f[1][l][r][i]=min(f[1][l][r][i],f[1][l][k][i-1]*mod(qzh[r]-qzh[k]));
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        maxn=max(maxn,f[0][i][i+n-1][m]);
        minn=min(minn,f[1][i][i+n-1][m]);
    }
}

int main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w"mstdout);
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>val[i];
        val[i+n]=val[i];
    }
    prepare();
    cout<<minn<<endl<<maxn<<endl;
    return 0;
}

P.S這道題有一點尷尬,就是我在做模擬賽的時候偷看了原來的程式,結果被老師看出來了。希望這是第一次,也是最後一次這種情況。(同學們千萬不能像我這樣,在考試的時候是不能翻看東西的,相反,考完試之後,要想盡一切方法去理解自己沒有搞懂的題目,千萬不要本末倒置。。。)

說實話,這道題比第二題簡單多了,就是一個普普通通的卡特蘭數,對於卡特蘭數,大家肯定都熟悉的不能再熟悉了,直接暴力上程式碼~~~

#include<iostream>
#include<cstdio> 
using namespace std;
int n,f[20][20];

void prepare()
{
    for(int i=1;i<=n;++i){
        f[i][0]=1;
        for(int j=1;j<=i;++j){
            f[i][j]=f[i-1][j]+f[i][j-1];
        }
    }
}

int main()
{
    freopen("stack.in","r",stdin);
    freopen("stack.out","w",stdout);
    cin>>n;
    prepare();
    cout<<f[n][n]<<endl;
}