NOIP2003年普及組題解
阿新 • • 發佈:2019-02-09
這是第一題: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;
}