zoukankan      html  css  js  c++  java
  • 【纪中受难记】——Day2.感觉冤的慌

    说实话,今天的题真的很简单。

    但是我……

    50/0/0/100。

    后来看看程序,发现是些很蠢的错误。。。还有没写的那些题,真的不难qwq


    1.佳肴:

    Description

      佳肴就是非常美味的菜的意思,佳肴最关键的是选择好原料。
      现在有N种原料,每种原料都有酸度S和苦度B两个属性,当选择多种原料时,总酸度为每种原料的酸度之积,总苦度为每种原料的苦度之和。
      正如大家所知,佳肴是既不酸也不苦的,因为要保证所选的原料使得总酸度和总苦度差的绝对值最小。
      由于佳肴不能只有水,所以必须至少选择一种佳肴。
     

    Input

      输入第一行包含一个整数N(1<=N<=10),表示原料的种数。
      接下来N行每行包含两个用一个空格隔开的整数,分别表示酸度和苦度。
      输入数据保证如果所有原料都选上,总酸度和总苦度不会超过10^9。

    Output

      输出总酸度和总苦度最小的差。

     

     

     

     

     

     

     

     

     

     

     

     

     

    这道题就是暴!搜!但是我起始点输了1,结果本来到了最后一组数据,当做越界处理了……

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int n;
     4 int a[12],b[12],minans=1e9,ans[1000],tg[1000],cnt;
     5 void dfs(int k,int mul,int sum,int tag){
     6     if(k>n) return;
     7     ans[++cnt]=min(minans,abs(mul-sum));
     8     tg[cnt]=tag;
     9     dfs(k+1,mul*a[k+1],sum+b[k+1],1);
    10     dfs(k+1,mul,sum,tag);
    11 }
    12 int main(){
    13     scanf("%d",&n);
    14     int oans=1e9;
    15     for(int i=1;i<=n;i++){
    16         scanf("%d%d",&a[i],&b[i]);
    17         oans=min(oans,abs(a[i]-b[i]));
    18     } 
    19     dfs(0,1,0,0);
    20     for(int i=1;i<=cnt;i++){
    21         if(!tg[i]) continue;
    22         if(ans[i]<oans) oans=ans[i];
    23     }
    24     printf("%d\n",oans);
    25     return 0;
    26 }

    2.取数游戏

    Description

      Alice想让Bob陪他去看《唐山大地震》,但由于Bob是个很感性的人,怕流泪不想去,但又不好意思以这个作为拒绝的理由,便提出玩一个游戏。
      N个正整数围成一圈,规则如下:
      •两个玩家轮流取数;
      •最开始先手的玩家可以取任意一个数x;
      •从第二步开始当前玩家只能取x(上一玩家刚刚取的数)左右两边相邻的数;
      •直到取完所有的数,游戏结束;
      •取得较多奇数的玩家获胜。
      Bob为了显示大度,让Alice先取,但他忘了自己和Alice都是绝顶聪明之人,现在Alice请你帮他计算第一步有多少种取法使得最终获得胜利。
     

    Input

      第一行包含一个整数N(1<=N<=100),表示数的个数。第二行包含N个正整数,每个数都在1到1000之间,任意两个数互不相同。

    Output

      输出Alice第一步有多少种取法。

    这道题很精妙,当你先取下一个数字后,剩下的数字就可以展开变成一个序列,每次都从序列的两边取,就变成区间dp了。

    对于博弈论的题目,设置dp要考虑每个人都是天才,取到的都是最优解。

    设s[i][j]表示区间中奇数个数,f[i][j]表示先手取i或j能获得的最大奇数个数,

    f[i][j]=max(s[i][j]-f[i+1][j],s[i][j]-f[i][j-1]),转移方向从里到外,s用前缀和优化。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=110;
    int n;
    int a[N*2];
    int s[N*2];
    int f[N][N],ans;
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            a[i]&=1;
        }
        for(int i=1;i<=n;i++){
            memset(f,0,sizeof(f));
            memset(s,0,sizeof(s));
            for(int j=1;j<=n;j++){
                s[j]=s[j-1]+a[j];
                f[j][j]=a[j];
            }
    //        for(int i=1;i<n;i++){
    //            for(int j=1;j+i<=n;j++){
    //                f[i][i+j]=max(s[i+j]-s[j-1]-f[j+1][i+j],s[i+j]-s[j-1]-f[j][i+j-1]);
    //            }
    //        }
            for(int k=1;k<=n-2;k++) { 
                for(int j=1;j+k<=n;j++) { 
                    int l=k+j; 
                    f[j][l]=max(s[l]-s[j-1]-f[j+1][l],s[l]-s[j-1]-f[j][l-1]); 
                } 
            } //
            f[1][n]=s[n]-f[2][n];
            if(s[n]/2+1<=f[1][n]) ans++;
            for(int i=0;i<=n;i++) a[i]=a[i+1];
            a[n]=a[0];
        }
        printf("%d\n",ans);
    //    for(int i=1;i<=n;i++){
    //        for(int j=1;j+i<=n*2;j++){
    //            f[j][j+i-1]=max(s[j+i]-s[j-1]-f[j+1][j+i-1],s[j+i]-s[j-1]-f[j][j+i-2]);
    //        }
    //    }
    //    for(int i=1;i<n;i++){
    //        for(int j=1;j+i<=n*2;j++){//l=j,r=j+i
    //            f[j][j+i]=max(s[j+i]-s[j-1]-f[j+1][j+i],s[j+i]-s[j-1]-f[j][j+i-1]); 
    //        }
    //    }
    //    for(int k = 1;k <= n - 2;k++) { 
    //            for(int j = 1;j <= 2*n - k;j++) { 
    //                int l = k + j; 
    //                f[j][l]=max(s[l]-s[j-1]-f[j+1][l],s[l]-s[j-1]-f[j][l-1]); 
    //            } 
    //    } 
    //    for(int i=1;i<=2*n;i++){
    //        cout<<a[i]<<" ";
    //    }
    //    for(int i=1;i<=2*n;i++){
    //        cout<<s[i]<<" ";
    //    }
    //    for(int i=1;i<=n;i++){
    //        if(s[i+n-1]-s[i-1]-f[i+1][i+n-1]>(n>>1)) ans++;
    //    }
    //    printf("%d",ans);
        
        return 0;
    }

    唯一一道不水的题目。

     

     

     


     

    3.删除

      这是道水题……但是当时没想到。

    Description

      Alice上化学课时又分心了,他首先画了一个3行N列的表格,然后把数字1到N填入表格的第一行,保证每个数只出现一次,另外两行他也填入数字1到N,但不限制每个数字的出现次数。
      Alice现在想删除若干列使得每一行排完序后完全一样,编程计算最少需要删除多少列。
     

    Input

      第一行包含一个整数N(1<=N<=100000),表示表格的列数。
      接下来三行每行包含N个整数,每个数在1到N之间,而且第一行的数互不相同。

    Output

      输出最少需要删除的列数。

     

     

     

     

     

     

      首先,对于一个表格,第二行和第三行不一定是全排列,就说明一定会有缺少的数字,我们用count记录一下。

      不断遍历1~n,找到第一行有而第二行or第三行没有的数字,最重要的是把第一行的对应数字归零(这样就不会判断到它),然后对应得一列删除。

      设置一个flag,判断每次删除情况,未删则跳出。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=1e5+10;
     4 int n;
     5 int ct1[N],ct2[N],ct3[N];
     6 int t2[N],t3[N],ans;
     7 int main(){
     8     scanf("%d",&n);
     9     for(int i=1;i<=n;i++){
    10         scanf("%d",&ct1[i]);
    11     }
    12     for(int i=1;i<=n;i++){
    13         scanf("%d",&ct2[i]);
    14         t2[ct2[i]]++;
    15     }
    16     for(int i=1;i<=n;i++){
    17         scanf("%d",&ct3[i]);
    18         t3[ct3[i]]++;
    19     }
    20     bool flag=false;
    21     while(!flag){
    22         flag=true;
    23         for(int i=1;i<=n;i++){
    24             if(ct1[i]&&!(t2[ct1[i]]&&t3[ct1[i]])){
    25                 flag=false;
    26                 ct1[i]=0;
    27                 ans++;
    28                 t2[ct2[i]]--;
    29                 t3[ct3[i]]--;
    30             }
    31         }
    32     }
    33     printf("%d",ans);
    34     return 0;
    35 }

    4.区间

    Description

      Alice收到一些很特别的生日礼物:区间。即使很无聊,Alice还是能想出关于区间的很多游戏,其中一个是,Alice从中选出最长的不同区间的序列,其中满足每个区间必须在礼物中,另序列中每个区间必须包含下一个区间。
      编程计算最长序列的长度。
     

    Input

      输入文件第一行包含一个整数N(1<=N<=100000),表示区间的个数。
      接下来N行,每行两个整数A和B描述一个区间(1<=A<=B<=1000000)。

    Output

      输出满足条件的序列的最大长度。

    这道题用了一点贪心的思想,我们将右端从大到小排序,这样遍历只用考虑左端点即可。

    考虑包含关系,每一个左端点都要比上一个左端点大,所以就是找最长不下降子序列的问题了。

    这里复习一下:

      我们用len表示答案长度,或者说答案区间的长度,遍历数组,每测到一个新的值,就与答案数组的len位置比较,如果大于ans[len],则直接令ans[++len]=a[i],即更新答案长度,但是如果小于,则在答案数组中找到一个比这个数大的第一个数与之替换(因为本来也可以绕过那个数到达这个数,且不会影响答案)(这里使用upper_bound,注意返回的是地址,要减去初地址(如果是数组就减去数组名称)),然后没了。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=1e6+10;
     4 struct line{
     5     int l,r;
     6 }a[N];
     7 int n,f[N];
     8 bool cmp(line t1,line t2){
     9     if(t1.r==t2.r) return t1.l<t2.l;
    10     else return t1.r>t2.r;
    11 }
    12 int main(){
    13     scanf("%d",&n);
    14     for(int i=1;i<=n;i++){
    15         scanf("%d%d",&a[i].l,&a[i].r);
    16     }
    17     sort(a+1,a+n+1,cmp);
    18     f[1]=a[1].l;
    19     int len=1;
    20     for(int i=2;i<=n;i++){
    21         if(a[i].l>=f[len]) f[++len]=a[i].l;
    22         else{
    23             int j=upper_bound(f+1,f+len+1,a[i].l)-f;
    24             f[j]=a[i].l;
    25         }
    26     }
    27     printf("%d\n",len);
    28     return 0;
    29 }

    总结:还是很菜,明天继续。

    ——抓住了时间,却不会利用的人,终究也逃不过失败的命运。
  • 相关阅读:
    防火墙透明模式
    HP管理工具System Management Homepage安装配置
    kbmmw 中JSON 中使用SQL 查询
    kbmmw 中JSON 操作入门
    第一个kbmmw for Linux 服务器
    kbmmw 5.02发布
    kbmmw 5.01 发布
    使用delphi 10.2 开发linux 上的Daemon
    使用unidac 在linux 上无驱动直接访问MS SQL SERVER
    使用delphi 10.2 开发linux 上的webservice
  • 原文地址:https://www.cnblogs.com/Nelson992770019/p/11290892.html
Copyright © 2011-2022 走看看