• 2017-10-2 清北刷题冲刺班p.m


    最大值

    (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<iostream>
    #include<cstdio>
    #define maxn 100010
    using namespace std;
    int n,k,a[maxn],x,y;
    long long sum[maxn],mx;
    int main(){
        //freopen("Cola.txt","r",stdin);
        freopen("max.in","r",stdin);freopen("max.out","w",stdout);
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        long long sum1,sum2;
        for(int s1=1;s1<=n-2*k+1;s1++){
            sum1=sum[s1+k-1]-sum[s1-1];
            for(int s2=s1+k;s2<=n-k+1;s2++){
                sum2=sum[s2+k-1]-sum[s2-1];
                if(sum1+sum2>mx){
                    mx=sum1+sum2;
                    x=s1,y=s2;
                }
            }
        }
        printf("%d %d",x,y);
        fclose(stdin);fclose(stdout);
        return 0;
    }
    60分 暴力
    /*
        b[i]表示左端点在i长度为k的区间这个和是多少
        找一个x,找一个y,使得x+k<=y,并且y+k-1<=n  并且b[x]+b[y]最大
        
        当固定x的时候,  x+k<=y<=n-k+1  区间求最大  ->  线段树/倍增表    nlgn
        当x从大变小的时候,  y解锁了一个位置  拿这个数来更新b[y]的最大值  O(n) 
    */
    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,m,a[200005],i,ansx,ansy;
    long long  sum[200005],MAX,MAX1[200005],MAX2[200005],x2[200005],x1[200005];
    int main()
    {
        freopen("max.in","r",stdin);
        freopen("max.out","w",stdout);
        scanf("%d%d",&n,&m);
        for (i=1; i<=n; i++) scanf("%d",&a[i]);
        for (i=1; i<=n; i++)
            sum[i]=sum[i-1]+(long long)a[i];
       // return 0;
        for (i=m; i<=n; i++)
        {
            //if (i%1000==0)cout<<i<<endl;
            if (MAX1[i-1]>=sum[i]-sum[i-m])
            {
                x1[i]=x1[i-1];
                MAX1[i]=MAX1[i-1];
            }
            else
            {
                x1[i]=i-m+1;
                MAX1[i]=sum[i]-sum[i-m];
            }
        }
        for (i=n-m+1; i>=1; i--)
        {
            if (MAX2[i+1]>sum[i+m-1]-sum[i-1])
            {
                x2[i]=x2[i+1];
                MAX2[i]=MAX2[i+1];
            }
            else
            {
                x2[i]=i;
                MAX2[i]=sum[i+m-1]-sum[i-1];
            }
        }
        for (i=m; i<=n-m; i++)
        {
            if (MAX1[i]+MAX2[i+1]>MAX)
            {
                MAX=MAX1[i]+MAX2[i+1];
                ansx=x1[i]; ansy=x2[i+1];
            }
        }
        printf("%d %d
    ",ansx,ansy);
        return 0;
    }
    100分 前缀和+线段树/倍增表

    吃东西

    (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<=100000000,1<=A,B,C,D<=5000,0<=ai,bi,ci,di<=100000000。

    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #include<algorithm>
    #define maxn 5010
    using namespace std;
    int n,A,B,C,D,a[maxn],b[maxn],c[maxn],d[maxn],cnt;
    long long v[25000010],ans;
    int find(int x){
        int l=1,r=cnt,res=0;
        while(l<=r){
            int mid=(l+r)>>1;
            if(v[mid]<=x)res=mid,l=mid+1;
            else r=mid-1;
        }
        return res;
    }
    int main(){
        //freopen("data.txt","r",stdin);
        freopen("eat.in","r",stdin);freopen("eat.out","w",stdout);
        scanf("%d%d%d%d%d",&n,&A,&B,&C,&D);
        for(int i=1;i<=A;i++)scanf("%d",&a[i]);
        for(int i=1;i<=B;i++)scanf("%d",&b[i]);
        for(int i=1;i<=C;i++)scanf("%d",&c[i]);
        for(int i=1;i<=D;i++)scanf("%d",&d[i]);
        sort(a+1,a+A+1);sort(b+1,b+B+1);
        sort(c+1,c+C+1);sort(d+1,d+D+1);
        if(a[A]+b[B]+c[C]+d[D]<=n){
            ans=1LL*A*B*C*D;
            cout<<ans;
            return 0;
        }
        for(int i=1;i<=A;i++){
            if(a[i]>n)break;
            for(int j=1;j<=B;j++){
                if(a[i]+b[j]>n)break;
                v[++cnt]=a[i]+b[j];
            }
        }
        sort(v+1,v+cnt+1);
        for(int i=1;i<=C;i++){
            if(c[i]>n)break;
            for(int j=1;j<=D;j++){
                if(c[i]+d[j]>n)break;
                int pos=find(n-c[i]-d[j]);//小于等于某数的最后一个位置 
                ans+=pos;
            }
        }
        cout<<ans;
        fclose(stdin);fclose(stdout);
        return 0;
    }
    70分 折半枚举
    /*
        1024MB*1024*1024/4 = 225000000个int数组
        A和B   C和D
                A和B和C和D
        
        A和B中的一种   C和D的一种
        A和B  双重循环  来得到一个f[i]表示花了i这个时间有几种可能  A*B
        进行桶排序,把f按次序的放进x数组中,A*B种可能排个序
        C和D  双重循环  来得到一个g[i]表示花了i这个时间有几种可能  C*D 
        进行桶排序,把g按次序的放进y数组中,C*D种可能排个序
        A*B 一个数组x   C*D的一个数组y   查询存在多少对i,j,使得x[i]+y[j]<=n  (x和y都是有序的)
        x和y都是顺序的。
        
        x[1]  y[?]  一个前缀(1~p) 
        x[2]  y[??]  一个前缀(1~pp)  pp<=p
        x[3]  y[???] 一个前缀(1~ppp)  ppp<=pp
        
        当一个规模解决不了的时候,分成两半  meet in the middle
    
    */
    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <cstring>
    using namespace std;
    int f[100000005],c[25000005],cc[25000005];
    int A,B,C,D,n,a[5005],b[5005],aa[5005],bb[5005],MAX,cnt,cntt,i,j,now;
    long long ans;
    int main()
    {
        freopen("eat.in","r",stdin);
        freopen("eat.out","w",stdout);
        scanf("%d%d%d%d%d",&n,&A,&B,&C,&D);
        if (n==0 && A==0 && B==0 && C==0 && D==0) return 0;
        for (i=1; i<=A; i++) scanf("%d",&a[i]);
        for (i=1; i<=B; i++) scanf("%d",&b[i]);
        MAX=0;
        cnt=cntt=0;
        for (i=1; i<=A; i++)
            for (j=1; j<=B; j++)
                if (a[i]+b[j]<=n)
                {
                    f[a[i]+b[j]]++;
                    MAX=max(MAX,a[i]+b[j]);
                }
        for (i=0; i<=MAX; i++)
        while (f[i])
            {
                f[i]--;
                c[++cnt]=i;
            }
    
        for (i=1; i<=C; i++) scanf("%d",&aa[i]);
        for (i=1; i<=D; i++) scanf("%d",&bb[i]);
        MAX=0;
        for (i=1; i<=C; i++)
            for (j=1; j<=D; j++)
                if (aa[i]+bb[j]<=n)
                {
                    f[aa[i]+bb[j]]++;
                    MAX=max(MAX,aa[i]+bb[j]);
                }
        for (i=0; i<=MAX; i++)
        while (f[i])
            {
                f[i]--;
                cc[++cntt]=i;
            }
        for (i=cntt; i>=1; i--) if (c[1]+cc[i]<=n) break;
        now=i;
        for (i=1; i<=cnt; i++)
        {
            ans+=now;
            while (now&& c[i+1]+cc[now]>n) now--;
        }
        cout<<ans<<endl;
        ans=0;
        return 0;
    }
    100分 meet in the middle

    分糖果

    (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。

    #include<iostream>
    #include<cstdio>
    #define mod 12345647
    using namespace std;
    int n,k,ans;
    bool check(int x){
        while(x){
            if(x%10==3)return 0;
            x/=10;
        }
        return 1;
    }
    int main(){
        freopen("candy.in","r",stdin);freopen("candy.out","w",stdout);
        scanf("%d%d",&n,&k);
        for(int i=k;i<=n-k-k;i++){
            for(int j=k;i+j<=n-k;j++){
                int k=n-i-j;
                if(check(i)&&check(j)&&check(k))ans++;
                if(ans>=mod)ans-=mod;
            }
        }
        cout<<ans;
        fclose(stdin);fclose(stdout);
        return 0;
    }
    50分 暴力
    /*
        枚举两个数,第三个数是确定,判断一下。
        
        f[i]表示i这个数字是否有3
        
        dp[i][j][0/1][0/1][0/1]来表示当前从高到低第i位,并且这一位需要向它的高位进j位   j=[0,2]  这3个数分别是否超过了k
        
        for (i=1; i<=|a|; i++)
        for (j=0; j<=2; j++)
        for (u=0; u<=1; u++)
        for (v=0; v<=1; v++)
        for (w=0; w<=1; w++)
        for (x=0; x<=9; x++)
          for (y=0; y<=9; y++)
            for (z=0; z<=9; z++)
            if (x+y+z>=10*j && x!=3 && y!=3 && z!=3) 
            {
              int k=x+y+z-10*j;
              if (k==a[i]) {dp[i+1][0][][][]+=dp[i][j];}
              if (k==a[i]-1) {dp[i+1][1][][][]+=dp[i][j];}
              if (k==a[i]-2) {dp[i+1][2][][][]+=dp[i][j];}
            }
        n=|a|
        cout<<dp[n][0];
    */
    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <cstring>
    using namespace std;
    const int MOD=12345647;
    int dp[10005][3][2][2][2],a[10005],b[10005],len1,len2,i,j,k,l,t,I,J,K,L,T,s1,s2,s3,ans;
    char n[10005],LL[10005];
    void ADD(int &A,int B) {A+=B; if (A>=MOD) A-=MOD;}
    int main()
    {
            freopen("candy.in","r",stdin);
            freopen("candy.out","w",stdout);
            scanf("%s",n);
            scanf("%s",LL);
            len1=strlen(n); len2=strlen(LL);
            for (i=0; i<len1; i++) a[i+1]=n[i]-'0';
            for (i=0; i<len1; i++) b[i+1]=0;
            for (i=0; i<len2; i++) b[1+i+len1-len2]=LL[i]-'0';
            for (i=0; i<=len1; i++)
              for (j=0; j<=2; j++)
                for (k=0; k<=1; k++)
                  for (l=0; l<=1; l++)
                    for (t=0; t<=1; t++) dp[i][j][k][l][t]=0;
            dp[0][0][0][0][0]=1;
            for (i=0; i<len1; i++)
              for (j=0; j<=2; j++)
                for (k=0; k<=1; k++)
                  for (l=0; l<=1; l++)
                    for (t=0; t<=1; t++)
                    if (dp[i][j][k][l][t])
                    {
                        for (s1=0; s1<=9; s1++)
                          if (s1!=3)
                            for (s2=0; s2<=9; s2++)
                              if (s2!=3)
                                for (s3=0; s3<=9; s3++)
                                if (s3!=3)
                                {
                                    I=i+1;
                                    J=j*10+a[i+1]-s1-s2-s3;
                                    if (J>2 || J<0) continue;
                                    if (k==0 && s1<b[i+1]) continue;
                                    K=(k || s1>b[i+1]);
                                    if (l==0 && s2<b[i+1]) continue;
                                    L=(l || s2>b[i+1]);
                                    if (t==0 && s3<b[i+1]) continue;
                                    T=(t || s3>b[i+1]);
                                    ADD(dp[I][J][K][L][T],dp[i][j][k][l][t]);
                                }
                    }
            for (k=0; k<=1; k++) for (l=0; l<=1; l++) for (t=0; t<=1; t++) ADD(ans,dp[len1][0][k][l][t]);
            cout<<ans<<endl; ans=0;
        return 0;
    }
    100分 数位dp
  • 相关阅读:
    Go 打印出结构化结构体
    GOPROXY设置
    python判断链表是否有环
    单链表python和go的代码
    mongo索引
    python修改srt字幕的时间轴
    python各个版本的排序
    mac使用python识别图形验证码
    selenium运行js代码笔记
    布隆过滤器
  • 原文地址:https://www.cnblogs.com/thmyl/p/7620306.html
Copyright © 2020-2023  润新知