【LDU】新生训练营杭电100题(三)

手机短号

水题不解释了:

代码如下:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        char str[1000]={0};
        scanf("%s",str);
        printf("6%s\n",str+6);
    }
    return 0;
}

找单词

提供两种做法:

第一种:母函数。

第二种:动态规划。

第一种:母函数    

具体可以参考:https://www.cnblogs.com/shentr/p/5347659.html

用到的正是普通母函数,其实说句老实话,母函数说起来非常吓人,

其实这个题就是用了点皮毛,具体还是需要自个写实现乘法组合问题。

扫描二维码关注公众号,回复: 2601886 查看本文章

G(x)=(1+x+x^2+...+x^a1 )* ( 1+x^2+x^4+..+x^(a2*2) +...+(1+X^26+...X^(26*a26));

三个for循环,我们需要把它展开即可。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        int x=1;
        int a[60]={0},b[60]={0};
        a[0]=1;
        for(int i=1;i<=26;i++){
            scanf("%d",&x);
            for(int j=0;j<=50;j++){
                for(int k=0;k<=x&&j+i*k<=50;k++){
                    b[j+i*k]=b[j+i*k]+a[j];
                }
            }
            for(int j=0;j<=50;j++){
                a[j]=b[j];
                b[j]=0;
            }
        }
        long long ans=0;
        for(int i=1;i<=50;i++){
            ans+=a[i];
        }
        printf("%lld\n",ans);
    }
    return 0;
}

第二种:dp[][]

往下延伸类似于   完全背包,但是多个完全背包,所以叫多重背包。

这个题目真的很意思。

今天看了一天真的不亏。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        int dp[60][60]={0},x;
        dp[0][0]=1;
        for(int i=1;i<=26;i++){
            scanf("%d",&x);
            for(int j=0;j<=50;j++){
                for(int k=0;k<=x&&j>=i*k;k++){
                    dp[i][j]+=dp[i-1][j-i*k];
                }
            }
        }
        long long ans=0;
        for(int i=1;i<=50;i++){
                ans+=dp[26][i];
        }
        printf("%lld\n",ans);
    }
}

C - 简易版之最短距离 

简单易懂:枚举从起点到终点每一个位置到所有位置之和。每个for循环

复杂度(500*N)

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        int a[5005];
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
        }
        sort(a,a+n);
        int minz=0x3f3f3f3f;
        for(int i=a[0];i<=a[n-1];i++){
            int t=0;
            for(int j=0;j<n;j++){
                t+=abs(i-a[j]);
            }
            minz=min(minz,t);
        }
        cout<<minz<<endl;
    }
    return 0;
}

D - 数塔 

有趣:这个题是我人生中的第一个DP题。

想法:

如果最下面的一层是最优的不会影响上面的抉择,

并且少了一层,那么问题就一步一步分解了。

我们每一层从下往上做到最优即可实现。

dp[i][j]+=max(dp[i+1][j],dp[i+1][j+1]);

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;
    cin>>T;
    while(T--){
        int n,a[105][105]={0},dp[105][105]={0};
        cin>>n;
        for(int i=0;i<n;i++){
            for(int j=0;j<=i;j++){
                scanf("%d",&a[i][j]);
            }
        }
        
        for(int i=n-2;i>=0;i--){
            for(int j=0;j<=i;j++){
                a[i][j]=a[i][j]+max(a[i+1][j],a[i+1][j+1]);
            }
        }
        
        printf("%d\n",a[0][0]);
    }
    return 0;
}

E - 核反应堆 

变种的斐波纳契数列:

G[i]=3*G[i-1]+2*D[i-1];    D[i]=G[i]+D[i];

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    int n;
    ll G[35],D[35];
    G[0]=1,D[0]=0;
    for(int i=1;i<=33;i++){
        G[i]=G[i-1]*3+D[i-1]*2;
        D[i]=G[i-1]+D[i-1];
    }
    while(~scanf("%d",&n),(n!=-1)){
        printf("%lld, %lld\n",G[n],D[n]);
    }
    return 0;
}

F - A1 = ? 

推公式即可

比较难想到,但是认真观察就足以。

例如n=5;

A1=(A0+A2)/2-C1;

A2=(A1+A3)/2-C2;

A3=(A2+A4)/2-C3;

A4=(A3+A5)/2-C4;

通过上面4个式子相加得:

(A1+A4)/2=(A0+A5)-(C1+C2+C3+C4)

以这个结论以此推出:

(A1+A4)/2=(A0+A5)-(C1+C2+C3+C4)

(A1+A3)/2=(A0+A4)-(C1+C2+C3)

(A1+A2)/2=(A0+A3)-(C1+C2)

(A1+A1)/2=(A0+A2)-(C1)

再来一遍累加:

5×A1/2=4×A0/2+A5/2-(4C1+3C2+2C3+C4)

推广到一般形式:

(N+1)A1/2=N×A0/2+A5/2-(N×C1+(N-1)×C2+......+Cn)

两边乘以2:

(N+1)A1=N×A0+A5-    2×(N×C1    +    (N-1)×C2+......+Cn    )

答案:

A1=[    N×A0+A5-    2×(N×C1    +    (N-1)×C2+......+Cn  )    ]    /    ( N+1 )

贴上代码:

#include<bits/stdc++.h>
using namespace  std;
int main()
{
    int n;
    double aN,a0,T,C[3005];
    while(~scanf("%d",&n)){
        cin>>a0>>aN;
        T=0;
        for(int i=n;i>=1;i--){
            cin>>C[i];
            T+=(i)*C[i];
        }
        double a1;
        a1=(n*a0+aN-2*T)/(n+1);
        printf("%.2lf\n",a1);
    }
    return 0;
}

G - 剪花布条 

考点:

1、输入                        cin.getline(a,sizeof(a),'\n')+sscanf(str,"%s %s",s1,s2)

2、匹配(BF算法)一一匹配即可,两个For循环头脑要清晰。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    char s[100005];
    char s1[100005],s2[100005];
    while(cin.getline(s,sizeof(s),'\n')){           //C++流输入getline
//while(scanf("%s",s1),(s1[0]=='#'&&strlen(s1)==1)?0:scanf("%s",s2))//普遍输入
        int n=strlen(s);
        if(s[0]=='#'&&n==1) return 0;
        sscanf(s,"%s %s",s1,s2);
                int n1=strlen(s1),n2=strlen(s2);
        //cout<<s1<<" "<<s2<<endl;
        int i,j,cnt=0;
        for(i=0;i<n1;i++){
            if(s1[i]==s2[0]){
                for(j=0;j<n2;j++){
                    if(s1[i+j]!=s2[j])
                        break;
                }
                if(j==n2){
                    i+=(n2-1);
                    cnt++;
                }
            }
        }
        printf("%d\n",cnt);
    }
    return 0;
}

H - Box of Bricks

 题解:

求出平均数和前缀和,如果每份多出来的地方累加,累加的结果就是答案。

解释:

因为需要得到平均值,必须拿走多余的地方,只考虑多的或者只考虑少的部分即可。

因为多的部分肯定会补到少的地方去。

所以这个得到的答案就是正解。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    while(~scanf("%d",&n),n){
        static int b=0;
        int a[10005],sum[10005]={0},aver;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            sum[i]=a[i]+sum[i-1];
        }
        aver=sum[n]/n;
        int ans=0;
        for(int i=1;i<=n;i++){
            if(a[i]>aver){          //if(aver>a[i])
                ans+=(a[i]-aver);   //ans+=(aver-a[i])
            }
        }
        if(b){
            cout<<endl;
        }else b++;
        cout<<ans<<endl;
    }
    return 0;
}

I - 不要62

题解:

这个题有多种方法,正解应该是数位DP(dfs,求不合法,只求合法)和暴力。

我先贴上代码,如果想看解释可以在我的博客里找一找。

正面求:

#include<bits/stdc++.h>
using namespace std;
int dp[10][10],d[10];
void init(){
    dp[0][0]=1;
    for(int i=1;i<7;i++){
        for(int j=0;j<=9;j++){
            for(int k=0;k<=9;k++){
                if((j!=4)&&!(j==6&&k==2)){
                    dp[i][j]+=dp[i-1][k];
                }
            }
        }
    }
}
int S(int x){
    int len=0;
    int ans=0;
    while(x){
        d[++len]=x%10;
        x/=10;
    }
    d[len+1]=0;
    for(int i=len;i>=1;i--){
        for(int j=0;j<d[i];j++){
            if(j!=4&&!(d[i+1]==6&&j==2)){
                ans+=dp[i][j];
            }
        }
        if(d[i]==4||(d[i+1]==6&&d[i]==2)){
            break;
        }
    }
    return ans;
}
int main()
{
    init();
    int n,m;
    while(~scanf("%d%d",&n,&m),(n||m)){
        int ans=S(m+1)-S(n);
        printf("%d\n",ans);
    }
    return 0;
}

 反面求:

#include<bits/stdc++.h>
using namespace std;
int dp[10][3]={0},d[10]={0};
void init(){
    dp[0][0]=1;
    for(int i=1;i<=8;i++){
        dp[i][0]=dp[i-1][0]*9-dp[i-1][1];
        dp[i][1]=dp[i-1][0];
        dp[i][2]=dp[i-1][2]*10+dp[i-1][1]+dp[i-1][0];
    }
}
int S(int x){
    int T=x,len=0;
    int flag=0;
    int cnt=0;
    for(;x;d[++len]=x%10,x/=10);
    d[len+1]=0;
    for(int i=len;i>0;i--){

        cnt +=( dp[i-1][2] * d[i] );

        if(flag){
            cnt += (dp[i-1][0]*d[i]);
        }else{
            if(d[i]>4)  cnt+=dp[i-1][0];

            if(d[i]>6)  cnt+=dp[i-1][1];

            if(d[i+1]==6&&d[i]>2)  cnt+=dp[i][1];
        }
        if(d[i]==4||(d[i+1]==6&&d[i]==2)){
                flag=1;
        }
    }
    return T-cnt;
}
int main()
{
    init();
    int n,m;
    while(~scanf("%d%d",&n,&m),(n||m)){
        int ans = S(m+1)-S(n);
        printf("%d\n",ans);
    }
    return 0;
}

正儿八经的数位DP:

#include<bits/stdc++.h>
using namespace std;
int a[10];
int dp[20][2];
int dfs(int pos,int pre,int sta,int limit){
    if(pos==-1) return 1;
    if(!limit&&dp[pos][sta]!=-1) return dp[pos][sta];
    int up=(limit?a[pos]:9);
    int tmp=0;
    for(int i=0;i<=up;i++){
        if( pre==6   && i==2) continue;
        if(i==4)    continue;
        tmp+=dfs(pos-1,i,i==6,limit&&i==a[pos]);
    }
    if(!limit)
        dp[pos][sta]=tmp;
    return tmp;
}
int solve(int x){
    int pos=0;
    while(x){
        a[pos++]=x%10;
        x/=10;
    }
    return dfs(pos-1,-1,1,true);
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m),(n||m)){
        memset(dp,-1,sizeof(dp));
        printf("%d\n",solve(m)-solve(n-1));
    }
    return 0;
}

J - 算菜价

题解:

这个题目考查了一样东西,就是某一位进行四舍五入。

格式:(int)(s×10+0.5) / 10.0

思考一下为什么这样???因为只要是0.5的话就会进一,如果没有就会向下取整而得到四舍的效果。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    char name[100];
    double n,m;
    double ans=0;
    while(~scanf("%s%lf%lf",name,&n,&m)){
            ans+=(n*m);
    }
    int T=(int)(ans*10+0.5);
    ans=T/10.0;
    printf("%.1lf\n",ans);
    return 0;
}

K - 空心三角形

 题解:

考查一下你输入格式,还有用草稿纸写一写规律即可。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    char s[3],ch;
    int n;
    static int m=0;
    while(~scanf("%s",s),(s[0]=='@'?0:scanf("%d",&n))){
        ch=s[0];
        char a[100][100]={0};
        for(int i=0;i<n-1;i++){
            for(int j=0;j<=(n-1)*2;j++){
                if(i+j==n-1){
                    a[i][j]=ch;
                }
                else if(j-i==n-1){
                    a[i][j]=ch;
                    a[i][j+1]='\0';
                    break;
                }
                else{
                    a[i][j]=' ';
                }
                if(i==0&&j==n){
                    a[i][j]='\0';
                }

            }
        }
        if(m)   printf("\n");
        else    m++;
        for(int i=0;i<2*n-1;i++){
            a[n-1][i]=ch;
        }a[n-1][2*n-1]='\0';
        for(int i=0;i<n;i++){
            printf("%s\n",a[i]);
        }
    }
    return 0;
}

L - 整数解

题解:

因为a,b的值比较小,可以通过枚举的方法来处理问题。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    ll a,b;
    while(~scanf("%lld%lld",&a,&b),(a||b)){
       int flag=0;
       for(int i=1;i<=abs(b);i++){
            if(abs(b)%i==0){
                if(b/i+i==a||b/(-i)-i==a){
                    flag=1;break;
                }
            }
       }
       flag?puts("Yes"):puts("No");
    }
    return 0;
}

M - 考试排名

这个题。。。。我光学了C语言是就搞不懂 

现在学了C++,真的好简单呀,就是处理的问题多了点罢了。

#include<bits/stdc++.h>
using namespace std;
typedef struct P{
    int Time,solved;
    char name[100];
    P (char nm[]=" ",int T=0,int S=0):Time(T),solved(S){
        strcpy(name,nm);
    }
    friend bool operator <(const P & a,const P & b);
}P;
bool operator <(const P & a,const P & b){
    string A=a.name,B=b.name;
    if(a.Time==b.Time  &&  a.solved==b.solved){
        return A<B;
    }
    if(a.solved==b.solved){
        return a.Time<b.Time;
    }
    return a.solved>b.solved;
}
P a[10000];
int main()
{
    char name[1000];
    int n,Ftime;
    int cnt=0;
    scanf("%d%d",&n,&Ftime);
    while(scanf("%s",name)!=EOF){
        char Problem[1000][100];
        strcpy(a[cnt].name,name);
        for(int i=0;i<n;i++){
            scanf("%s",Problem[i]);
            if(Problem[i][0]=='-'||Problem[i][0]=='0'){continue;}
            else{
                int T=0,C=0,flag=0;
                for(int j=0;j<strlen(Problem[i]);j++){
                    if(Problem[i][j]=='(')flag=1;
                }
                if(flag){
                    sscanf(Problem[i],"%d(%d)",&T,&C);
                    a[cnt].solved++;
                    a[cnt].Time+=(T+C*Ftime);
                }else{
                    sscanf(Problem[i],"%d",&T);
                    a[cnt].solved++;
                    a[cnt].Time+=(T);
                }
            }
        }
        cnt++;
    }
    sort(a,a+cnt);
    for(int i=0;i<cnt;i++)
    printf("%-10s%3d%5d\n",a[i].name,a[i].solved,a[i].Time);
    return 0;

}

/*
Josephus    5  376
John        4  284
Alice       4  352
Smith       3  167
Bob         2  325
Bush        0    0

Josephus    5  376
John        4  284
Alice       4  352
Smith       3  167
Bob         2  325
Bush        0    0
*/

N_产生冠军

题解:

通过观察可以知道,冠军不能出现在输的一方,而且冠军只有一个,所以总人数-输的人数==1就说明有冠军。

用set来维护一下就可以了。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    while(~scanf("%d",&n),n){
        string a[1005],b[1005];
        set<string>S1;
        set<string>S2;
        for(int i=0;i<n;i++){
            cin>>a[i]>>b[i];
            S1.insert(a[i]);
            S1.insert(b[i]);
            S2.insert(b[i]);
        }
        int sum=0;
        if(S1.size()-S2.size()==1){
            puts("Yes");
        }else{
            puts("No");
        }
    }
    return 0;
}

O - find your present (2)

题解:

利用异或来实现奇偶性问题。只要是出现的奇数性肯定会只有一个。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    while(~scanf("%d",&n),n){
        int ans=0,x;
        scanf("%d",&ans);
        for(int i=0;i<n-1;i++){
            scanf("%d",&x);
            ans^=x;
        }
        printf("%d\n",ans);
    }
    return 0;
}

P - 小明A+B

同余模定理:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    cin>>n;
    while(n--){
        int A,B;
        scanf("%d%d",&A,&B);
        int ans=(A%100+B%100)%100;
        cout<<ans<<endl;
    }
    return 0;
}

Q - Sky数

题解:

 用函数实现进制的转化即可。

#include<bits/stdc++.h>
using namespace std;
int ten_16(int x){
    int a[1000];
    int len=0,ans=0;
    while(x){
        ans+=(x%16);
        x/=16;
    }
    return ans;
}
int ten_12(int x){
    int a[1000];
    int len=0,ans=0;
    while(x){
        ans+=(x%12);
        x/=12;
    }
    return ans;
}
int ten_10(int x){
    int a[1000];
    int len=0,ans=0;
    while(x){
        ans+=(x%10);
        x/=10;
    }
    return ans;
}
int main()
{
    int n;
    while(~scanf("%d",&n),n){
        if(ten_10(n)==ten_12(n)&&ten_10(n)==ten_16(n)){
            printf("%d is a Sky Number.\n",n);
        }else{
            printf("%d is not a Sky Number.\n",n);
        }
    }
    return 0;
}

R - 分拆素数和

打一个线性素数表即可。 

#include<bits/stdc++.h>
using namespace std;
int prime[10005],x[100005],cnt=0;
const int N=100005;
void is_prime(){
    int t=0;
    for(int i=2;i<=N;i++){
        if(x[i]==0){
            prime[t++]=i;
            x[i]=1;
            for(int j=i+i;j<=N;j+=i){
                x[j]=2;
            }
        }
    }
    cnt=t;
}
int main()
{
    int n;
    is_prime();
    //cout<<cnt<<endl;
    while(~scanf("%d",&n),n){
        int ans=0;
        for(int i=0;prime[i]<=n;i++){
            if(x[n-prime[i]]==1){
                ans++;
            }
        }
        printf("%d\n",ans/2);
    }
    return 0;
}

S - 整除的尾数

 暴力枚举即可

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a,b;
    while(~scanf("%d%d",&a,&b),(a||b)){
            int cnt=0;
            int ans[1000]={0};
            for(int i=0;i<100;i++){
                int T=a*100+i;
                if(T%b==0){
                    ans[cnt++]=i;
                }
            }
            for(int i=0;i<cnt;i++){
                printf("%02d%c",ans[i],i==cnt-1?'\n':' ');
            }

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Z_sea/article/details/81047165