zoukankan      html  css  js  c++  java
  • 2017北京国庆刷题Day2 afternoon

    期望得分:100+100+50=250

    实际得分:100+70+50=220

    T1 最大值(max)

    Time Limit:1000ms   Memory Limit:128MB

    题目描述

    LYK有一本书,上面有很多有趣的OI问题。今天LYK看到了这么一道题目:

    这里有一个长度为n的正整数数列ai(下标为1~n)。并且有一个参数k。

    你需要找两个正整数x,y,使得x+k<=y,并且y+k-1<=n。并且要求a[x]+a[x+1]+…+a[x+k-1]+a[y]+a[y+1]+…+a[y+k-1]最大。

    LYK并不会做,于是它把题扔给了你。

    输入格式(max.in)

    第一行两个数n,k。

        第二行n个数,表示ai。

    输出格式(max.out)

    两个数表示x,y。若有很多种满足要求的答案,输出x最小的值,若x最小仍然还有很多种满足要求的答案,输出y最小的值。 

    输入样例

    5 2

    6 1 1 6 2

    输出样例

    1 4

    对于30%的数据n<=100。

    对于60%的数据n<=1000

    对于100%的数据1<=n<=100000,1<=k<=n/2,1<=ai<=10^9。

    维护连续的k个数的和 的后缀最大值

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define N 100001
    using namespace std;
    typedef long long LL;
    LL sum[N],p[N],suf[N];
    int pos[N];
    void read(LL &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    int main()
    {
        freopen("max.in","r",stdin);
        freopen("max.out","w",stdout);
        int n,k;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) read(sum[i]),sum[i]+=sum[i-1];
        for(int i=1;i+k-1<=n;i++) p[i]=sum[i+k-1]-sum[i-1];
        for(int i=n-k+1;i;i--) 
            if(p[i]>=suf[i+1]) suf[i]=p[i],pos[i]=i;
            else suf[i]=suf[i+1],pos[i]=pos[i+1];
        int ansx,ansy;
        LL maxn=0;
        for(int i=1;i+k+k-1<=n;i++)
            if(p[i]+suf[i+k]>maxn) maxn=p[i]+suf[i+k],ansx=i,ansy=pos[i+k];
            else if(p[i]+suf[i+k]==maxn && ansy>pos[i+k]) ansy=pos[i+k];
        printf("%d %d",ansx,ansy);
        return 0; 
    }
    View Code

    T2 吃东西(eat)

    Time Limit:2000ms   Memory Limit:1024MB

    题目描述

    一个神秘的村庄里有4家美食店。这四家店分别有A,B,C,D种不同的美食。LYK想在每一家店都吃其中一种美食。每种美食需要吃的时间可能是不一样的。

    现在给定第1家店A种不同的美食所需要吃的时间a1,a2,…,aA。

        给定第2家店B种不同的美食所需要吃的时间b1,b2,…,bB。

    以及c和d。

    LYK拥有n个时间,问它有几种吃的方案。

    输入格式(eat.in)

    第一行5个数分别表示n,A,B,C,D。

    第二行A个数分别表示ai。

    第三行B个数分别表示bi。

    第四行C个数分别表示ci。

    第五行D个数分别表示di。

    输出格式(eat.out)

    一个数表示答案。

    输入样例

    11 3 1 1 1

    4 5 6

    3

    2

    1

    输出样例

    2

    对于30%的数据A,B,C,D<=50

    对于另外30%的数据n<=1000。

    对于100%的数据1<=n<=1000000001<=A,B,C,D<=5000,0<=ai,bi,ci,di<=100000000。

    30% 枚举,另外30%分组背包

    100%的数据:注意空间1GB

    所以可以维护sum[i]表示 C+D 里面时间和为i 的方案数

    然后枚举A,B,累计n-A[i]-B[i] 的方案数

    #include<map>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    typedef long long LL;
    LL dp[5][1001];
    int cost[5][5001],n;
    int C[5001],D[5001],A[5001],B[5001]; 
    int sum[200000001]; 
    inline void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    } 
    void init()
    {
        read(n); read(cost[1][0]); read(cost[2][0]); read(cost[3][0]); read(cost[4][0]);
        for(int i=1;i<=cost[1][0];i++) read(cost[1][i]);
        for(int i=1;i<=cost[2][0];i++) read(cost[2][i]);
        for(int i=1;i<=cost[3][0];i++) read(cost[3][i]);
        for(int i=1;i<=cost[4][0];i++) read(cost[4][i]);
    } 
    void out(LL x)
    {
        if(x/10) out(x/10);
        putchar(x%10+'0'); 
    } 
    void work1()
    {
        for(int i=0;i<=n;i++) dp[0][i]=1;
        for(int k=1;k<=4;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=cost[k][0];j++)
                    if(i-cost[k][j]>=0) dp[k][i]+=dp[k-1][i-cost[k][j]];
        out(dp[4][n]);
    }
    void work2()
    {
        int ans=0;
        for(int i=1;i<=cost[1][0];i++)
            for(int j=1;j<=cost[2][0];j++)
                for(int k=1;k<=cost[3][0];k++)
                    for(int l=1;l<=cost[4][0];l++)
                        if(cost[1][i]+cost[2][j]+cost[3][k]+cost[4][l]<=n) ans++;
        printf("%d",ans);
    }
    void work3()
    {
        int cnt=0,sc=cost[3][0],sd=cost[4][0]; 
        for(int i=1;i<=sc;i++) C[i]=cost[3][i];
        for(int i=1;i<=sd;i++) D[i]=cost[4][i]; 
        int minn=2e8,maxn=0 ;
        for(int i=1;i<=sc;i++)
            for(int j=1;j<=sd;j++)
            {
                sum[C[i]+D[j]]++;
                minn=min(minn,C[i]+D[j]);
                maxn=max(maxn,C[i]+D[j]); 
            }
        for(int i=minn;i<=maxn;i++) sum[i]+=sum[i-1];
        int sa=cost[1][0],sb=cost[2][0]; 
        for(int i=1;i<=sa;i++) A[i]=cost[1][i];
        for(int i=1;i<=sb;i++) B[i]=cost[2][i];
        long long ans=0; 
        for(int i=1;i<=sa;i++)
            for(int j=1;j<=sb;j++)
                if(n-A[i]-B[j]>=0) ans+=sum[min(n-A[i]-B[j],maxn)];
        out(ans);      
    } 
    int main()
    {
        freopen("eat.in","r",stdin);
        freopen("eat.out","w",stdout); 
        init();
        if(cost[1][0]<=50 && cost[2][0]<=50 && cost[3][0]<=50 && cost[4][0]<=50) work2();
        else if(n<=1000) work1();
        else work3(); 
        return 0; 
    }
    View Code

    考场上分组背包 体积从1开始的,挂了

    数据里面有0

    T3  分糖果(candy)

    Time Limit:1000ms   Memory Limit:128MB

    题目描述

    总共有n颗糖果,有3个小朋友分别叫做L,Y,K。每个小朋友想拿到至少k颗糖果,但这三个小朋友有一个共同的特点:对3反感。也就是说,如果某个小朋友拿到3颗,13颗,31颗,333颗这样数量的糖果,他就会不开心。(也即它拿到的糖果数量不包含有一位是3)

    LYK掌管着这n颗糖果,它想问你有多少种合理的分配方案使得将这n颗糖果全部分给小朋友且没有小朋友不开心。

    例如当n=3,k=1时只有1种分配方案,当n=4,k=1时有3种分配方案分别是112,121,211。当n=7,k=2时则不存在任何一种合法的方案。

    当然这个答案可能会很大,你只需输出答案对12345647取模后的结果就可以了。

    输入格式(candy.in)

    第一行两个数表示n,k。

    输出格式(candy.out)

    一个数表示方案总数。

    输入样例

    99999 1

    输出样例

    9521331

    对于30%的数据n<=100

    对于50%的数据n<=1000。

    对于另外30%的数据k=1。

    对于100%的数据3<=n<=10^10000,1<=k<=n/3,且n,k不包含前导0。

    数位DP

    dp[i][j][k][l][t] 表示n的前i位,分完后的余数为j,第1/2/3个小朋友的第i位能否随便填 的方案数

    再枚举3个小朋友分别分多少转移

    #include<cstdio>
    #include<cstring>
    
    #define N 10003
    
    using namespace std;
    
    const int mod=12345647;
    
    char s[N];
    int a[N],b[N],dp[N][3][2][2][2];
    
    void ADD(int &i,int j)  {  i+=j; if(i>=mod) i-=mod; }
    
    int main()
    {
        freopen("candy.in","r",stdin);
        freopen("candy.out","w",stdout);
        scanf("%s",s+1); int len1=strlen(s+1);
        for(int i=1;i<=len1;++i) a[i]=s[i]-'0';
        scanf("%s",s+1); int len2=strlen(s+1);
        for(int i=1;i<=len2;++i) b[i+len1-len2]=s[i]-'0';
        dp[0][0][0][0][0]=1;
        int i,j,k,l,t,I,J,K,L,T;
        for(i=0;i<len1;i++)
          for(j=0;j<3;j++)
            for(k=0;k<2;k++)
              for(l=0;l<2;l++)
                for(t=0;t<2;t++)
                    if(dp[i][j][k][l][t])
                      for(int s1=0;s1<=9;s1++)
                        if(s1!=3)
                          for(int s2=0;s2<=9;s2++)
                            if(s2!=3)
                              for(int s3=0;s3<=9;s3++)
                                if(s3!=3)
                                {
                                    I=i+1;
                                    J=j*10+a[i+1]-s1-s2-s3;
                                    if(J<0 || J>2) continue;
                                    if(!k && s1<b[i+1]) continue;
                                    K=(k || s1>b[i+1]);
                                    if(!l && s2<b[i+1]) continue;
                                    L=(l || s2>b[i+1]);
                                    if(!t && s3<b[i+1]) continue;
                                    T=(t || s3>b[i+1]);
                                    ADD(dp[I][J][K][L][T],dp[i][j][k][l][t]);                    
                                }
        int ans=0;
        for(k=0;k<2;k++)
            for(l=0;l<2;l++)
                for(t=0;t<2;t++)
                    ADD(ans,dp[len1][0][k][l][t]);
        printf("%d",ans);                        
    }
    View Code

    考场50分做法:枚举第一个,枚举第二个,判断是否合法

    #include<cstdio>
    using namespace std;
    bool check(int k)
    {
        while(k)
        {
            if(k%10==3) return false;
            k/=10;
        }
        return true;
    }
    int main()
    {
        freopen("candy.in","r",stdin);
        freopen("candy.out","w",stdout);
        int n,k,ans=0;
        scanf("%d%d",&n,&k);
        for(int i=k;i+k+k<=n;i++)
            if(check(i))
                for(int j=k;j+i+k<=n;j++)
                    if(check(j)&&check(n-i-j)) ans++;
        printf("%d",ans);
        return 0; 
    }
    View Code
  • 相关阅读:
    C#学习笔记:多态与隐藏,覆盖
    HTML与XML数据的结合小总结
    基于角色(RoleBased)的表单验证
    去除C++String的首尾空格
    Bash Shell中命令行选项/参数处理
    linux shell 执行多个命令的几种方法
    gdb 多线程调试
    linux 时间戳及时间差计算
    oracle sql日期比较
    在Fedora 14上安装Sun JDK 6
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7639547.html
Copyright © 2011-2022 走看看