【纪中受难记】——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 }

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

猜你喜欢

转载自www.cnblogs.com/Nelson992770019/p/11290892.html