1. 程式人生 > >9.1模擬賽

9.1模擬賽

use spa ring 出現 由於 允許 lan 包含 %d

T1 生日蛋糕

傳送門

題目背景

7月17日是Mr.W的生日,ACM-THU為此要制作一個體積為Nπ的M層

生日蛋糕,每層都是一個圓柱體。

設從下往上數第i(1<=i<=M)層蛋糕是半徑為Ri, 高度為Hi的圓柱。當i<M時,要求Ri>Ri+1且Hi>Hi+1。

由於要在蛋糕上抹奶油,為盡可能節約經費,我們希望蛋糕外表面(最下一層的下底面除外)的面積Q最小。

令Q= Sπ

請編程對給出的N和M,找出蛋糕的制作方案(適當的Ri和Hi的值),使S最小。

(除Q外,以上所有數據皆為正整數)

題目描述

技術分享

輸入輸出格式

輸入格式:

有兩行,第一行為N(N<=20000),表示待制作的蛋糕的體積為Nπ;第二行為M(M<=15),表示蛋糕的層數為M。

輸出格式:

僅一行,是一個正整數S(若無解則S=0)。

輸入輸出樣例

輸入樣例#1:
100
2
輸出樣例#1:
68


題解 搜索+剪枝
代碼
(1)T了九個點...QAQ
#include<iostream>
#include<cstdio>
#include<cmath>
#define inf 0x7fffffff
using namespace std;

int n,m,ans;

void dfs(int w,int h,int r,int v,int s) {
    if(s>ans)return;
    if(v>n)return
; if(h<=(m-w)||r<=(m-w))return; if(w==m){if(v==n)ans=min(ans,s);return;} for(int i=h-1;i>=(m-w);i--) for(int j=(m-w);j<=r-1;j++) if(w==0)dfs(w+1,i,j,v+j*j*i,s+2*j*i+j*j); else dfs(w+1,i,j,v+j*j*i,s+2*j*i); return; } int main(){ // freopen("cake.in","r",stdin);
// freopen("cake.out","w",stdout); scanf("%d",&n);//制作蛋糕的體積。 scanf("%d",&m);//制作蛋糕的層數。 int r=sqrt(n)+1; ans=inf; dfs(0,n,n,0,0); if(ans==inf)printf("0\n"); else printf("%d\n",ans); return 0; }

(2)AC代碼

可行性剪枝:

建好的體積加上最少的建完的體積仍大於n return

建好的體積大於n return

最優性剪枝:

當前面積加上建完的最小面積大於當前最優解 return

當前面積大於最優解return

#include<iostream>
#include<cstdio>
using namespace std;
int minv[25],mins[25],ans=1e9;
int n,m;
void dfs(int v,int s,int flr,int lowr,int lowh)//已經建好的體積,面積,還剩下的層數,已經建好的上一層的r和h 
{
    if(flr==0){
        if(s<ans&&v==n)ans=s;
        return;
    }
    if(v+minv[flr]>n||s+mins[flr]>ans||v>n||s>ans)return; 
    if((n-v)/lowr*2+s>ans)return;
    for(int i=lowr-1;i>=flr;i--)
    {
        if(flr==m)s=i*i;
        int mxh=min(lowh-1,(n-v-minv[flr-1])/(i*i));
        for(int j=mxh;j>=flr;j--)
        dfs(v+i*i*j,s+2*i*j,flr-1,i,j);
    }
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        minv[i]=minv[i-1]+i*i*i;//從頂上數i個的最小體積 
        mins[i]=mins[i-1]+i*i*2;//同 最小側面積 
    }
    dfs(0,0,m,n+1,n+1);
    printf("%d\n",ans);
    return 0;
}

T2 蟲食算

傳送門

題目描述

所謂蟲食算,就是原先的算式中有一部分被蟲子啃掉了,需要我們根據剩下的數字來判定被啃掉的字母。來看一個簡單的例子:

43#9865#045

+8468#6633

44445509678

其中#號代表被蟲子啃掉的數字。根據算式,我們很容易判斷:第一行的兩個數字分別是5和3,第二行的數字是5。

現在,我們對問題做兩個限制:

首先,我們只考慮加法的蟲食算。這裏的加法是N進制加法,算式中三個數都有N位,允許有前導的0。

其次,蟲子把所有的數都啃光了,我們只知道哪些數字是相同的,我們將相同的數字用相同的字母表示,不同的數字用不同的字母表示。如果這個算式是N進制的,我們就取英文字母表午的前N個大寫字母來表示這個算式中的0到N-1這N個不同的數字:但是這N個字母並不一定順序地代表0到N-1)。輸入數據保證N個字母分別至少出現一次。

BADC

  • CBDA

DCCC 上面的算式是一個4進制的算式。很顯然,我們只要讓ABCD分別代表0123,便可以讓這個式子成立了。你的任務是,對於給定的N進制加法算式,求出N個不同的字母分別代表的數字,使得該加法算式成立。輸入數據保證有且僅有一組解

輸入輸出格式

輸入格式:

包含四行。第一行有一個正整數N(N<=26),後面的3行每行有一個由大寫字母組成的字符串,分別代表兩個加數以及和。這3個字符串左右兩端都沒有空格,從高位到低位,並且恰好有N位。

輸出格式:

包含一行。在這一行中,應當包含唯一的那組解。解是這樣表示的:輸出N個數字,分別表示A,B,C……所代表的數字,相鄰的兩個數字用一個空格隔開,不能有多余的空格。

輸入輸出樣例

輸入樣例#1:
5
ABCED
BDACE
EBBAA
輸出樣例#1:
1 0 3 4 2

說明

對於30%的數據,保證有N<=10;

對於50%的數據,保證有N<=15;

對於全部的數據,保證有N<=26。

noip2004提高組第4題

題解

暴搜

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm> 
using namespace std;

int use[29],k[29],q[29][5],las[29];
int n;char x;

inline void print(){
    for(int i=1;i<=n;i++)printf("%d ",k[i]);
    exit(0);
}

inline int check1(int px){
    for(int i=n;i>=px+1;i--){
        if(k[q[px][1]]!=-1&&k[q[px][2]]!=-1&&k[q[px][3]]!=-1){
        //    if((k[q[px][1]]+k[q[px][2]]+las[px-1])%n!=k[q[px][3]])
        if((k[q[px][1]]+k[q[px][2]])%n!=k[q[px][3]]&&(k[q[px][1]]+k[q[px][2]]+1)%n!=k[q[px][3]])
            return false;
        }
    }
    return true;
}

int check2(int px){
    if(k[q[px][1]]!=-1&&k[q[px][2]]!=-1&&k[q[px][3]]!=-1){
        if((k[q[px][1]]+k[q[px][2]]+las[px-1])%n!=k[q[px][3]]){
            return false;
        }else las[px]=(k[q[px][1]]+k[q[px][2]]+las[px-1])/n;
    }
    if(k[q[px][1]]!=-1&&k[q[px][2]]!=-1&&k[q[px][3]]==-1){
        int z=(k[q[px][1]]+k[q[px][2]]+las[px-1])%n;
        if(use[z])return false;
    }
    if(k[q[px][1]]==-1&&k[q[px][3]]!=-1&&k[q[px][2]]!=-1){
        int z=(k[q[px][3]]-k[q[px][2]]-las[px-1]+n)%n;
        if(use[z])return false;
    }
    if(k[q[px][2]]==-1&&k[q[px][1]]!=-1&&k[q[px][2]]!=-1){
        int z=(k[q[px][3]]-k[q[px][1]]-las[px-1]+n)%n;
        if(use[z])return false;
    }
    return true;
}

void dfs(int posx,int posy){
    if(k[q[posx][posy]]==-1){
        if(posy==1||posy==2)
        for(register int i=n-1;i>=0;i--){
            if(use[i]==0){
                use[i]=1;k[q[posx][posy]]=i;
                if(check1(posx)&&check2(posx))dfs(posx,posy+1);
                use[i]=0;k[q[posx][posy]]=-1;
            }
        }else{
            int z=k[q[posx][1]]+k[q[posx][2]]+las[posx-1];
            if(z>=n)z%=n;
            if(use[z]==0){
                use[z]=1;k[q[posx][posy]]=z;
                if(posx==n)print();
                if(check1(posx)&&check2(posx))
                dfs(posx+1,1);
                use[z]=0;k[q[posx][posy]]=-1;
            }
        }
    }else{
        if(check1(posx)&&check2(posx)){
            if(posx==n&&posy==3)print();
            if(posy==1||posy==2)dfs(posx,posy+1);
            else dfs(posx+1,1);
        }
    }
}

int main(){
    scanf("%d",&n);scanf("\n");
    register int i;
    for(i=1;i<=n;i++){scanf("%c",&x);q[i][1]=x-A+1;}
    scanf("\n");
    for( i=1;i<=n;i++){scanf("%c",&x);q[i][2]=x-A+1;}
    scanf("\n");
    for(i=1;i<=n;i++){scanf("%c",&x);q[i][3]=x-A+1;}
    for(i=1;i<=n/2;i++)
    {swap(q[i][1],q[n-i+1][1]);swap(q[i][2],q[n-i+1][2]);swap(q[i][3],q[n-i+1][3]);}
    memset(k,-1,sizeof(k));
    dfs(1,1);
    return 0;
}

 

9.1模擬賽