• 2016.6.10测试


    1、汽艇(Boat.cpp/c/pas)
    【问题描述】
    有 n 个人要去坐 1 汽艇,每个人单独坐汽艇的快乐程度是 Ci,每多一个人,他的快乐程度会减去 Di,请求出使快乐程度之和达到最大的方案。(假设汽艇的容量足够大)。
    【输入格式】
    输入文件共有 3 行:
    第1 行是一个整数 n;
    第2 行有n 个整数,依次表示每个人单独坐汽艇的快乐程度 Ci(1<=Ci<=10000);
    第3 行有n 个整数,依次表示每多 1 人,每个人快乐程度的下降值 Di(1<=Di<=10)。
    【输出格式】
    应输出两行:
    第1 行一个整数,是最大的快乐程度之和;
    第2 行一个整数,是最大的快乐程度之和所对应的汽艇上的人数(若有多种方案,则输出人数最多的)。
    【输入样例】
    6
    10 10 10 10 10 9
    2 2 2 2 2 3
    【输出样例】
    18
    3
    【样例说明】
    前 3 个人去坐汽艇可使快乐程度之和达到最大,每个人的快乐程度均为 10-2*2=6,总和是
    18。
    【数据范围】
    对于 30%的数据,n<=20;
    对于 100%的数据,n<=1000。

    正解:贪心

    解题报告:

      标准水题,枚举有多少个人,然后每次sort,取最优的情况即可。  

     1 //It is made by jump~
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <algorithm>
     8 #include <ctime>
     9 #include <vector>
    10 #include <queue>
    11 #include <map>
    12 #include <set>
    13 #ifdef WIN32   
    14 #define OT "%I64d"
    15 #else
    16 #define OT "%lld"
    17 #endif
    18 using namespace std;
    19 typedef long long LL;
    20 const int MAXN = 1011;
    21 int n,ans,cnt,jilu;
    22 
    23 struct node{
    24     int val;
    25     int fall;
    26 }a[MAXN];
    27 
    28 struct now{
    29     int val;
    30 }jump[MAXN];
    31 
    32 inline int getint()
    33 {
    34        int w=0,q=0;
    35        char c=getchar();
    36        while((c<'0' || c>'9') && c!='-') c=getchar();
    37        if (c=='-')  q=1, c=getchar();
    38        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
    39        return q ? -w : w;
    40 }
    41 
    42 inline bool cmp(node q,node qq){ return q.val>qq.val; }
    43 
    44 inline bool ccmp(now q,now qq){ return q.val>qq.val; }
    45 
    46 inline void solve(){
    47     n=getint();
    48 
    49     for(int i=1;i<=n;i++) a[i].val=getint();
    50 
    51     for(int i=1;i<=n;i++) a[i].fall=getint();
    52 
    53     sort(a+1,a+n+1,cmp); ans=a[1].val; jilu=1;
    54     for(int i=2;i<=n;i++) {
    55     for(int j=1;j<=n;j++) jump[j].val=a[j].val-(i-1)*a[j].fall;
    56     sort(jump+1,jump+n+1,ccmp);
    57     cnt=0;
    58     for(int j=1;j<=i;j++)  cnt+=jump[j].val;
    59     if(cnt>=ans) {
    60         ans=cnt;
    61         jilu=i;
    62     }
    63     }
    64     printf("%d
    %d",ans,jilu);
    65 }
    66 
    67 int main()
    68 {
    69   solve();
    70   return 0;
    71 }


    2、上网(net.cpp/c/pas)

    【问题描述】
    假设有 n 个人要上网,却只有 1 台电脑可以上网。上网的时间是从 1 szw 至 T szw ,szw是一个自创的时间单位,至于 szw怎么换算成 s,min 或 h,没有人清楚。依次给出每个人在某个时间段内上网的快乐程度 C(必须这个人在整个时间段内都在上网,才能获得快乐程度C,否则,快乐程度是 0),请你得到使总的快乐程度达到最大的方案。
    【输入格式】
    第1 行2 个整数 n和 T,含义如题目所述;
    接下来有 n 个这样的结构(每两个相邻的结构之间有一空行,且第 1 个结构和第一行间有
    一空行):
    第1 行一个整数 Mi,表示第 i 个人的时间段的个数;
    接下来有 Mi 行,每行3个整数 Xj,Yj,C,表示第 i个人在[Xj,Yj]内上网的快乐程度为 C,
    因此有 Xj-Yj-1=1,X1=1,Ymi=T,Xj<=Yj。
    【输出格式】
    仅输出一行,为总的最大的快乐程度。
    【输入样例】
    3 10
    3
    1 3 6
    4 7 9
    8 10 3
    3
    1 3 5
    4 7 10
    8 10 1
    4
    1 3 2
    4 8 2
    9 9 6
    10 10 3
    【输出样例】
    25
    【样例说明】
    在[1,3]内,安排 1 上网,快乐程度为 6;
    在[4,7]内,安排 2 上网,快乐程度为 10; 在[8,8]内,不安排;
    在[9,9]内,安排 3 上网,快乐程度为 6;
    在[10,10]内,安排 3 上网,快乐程度为 3;
    这是使总的快乐程度达到最大的方案,对应的值是 25。
    【数据范围】
    对于 30%的数据,n<=4,所有的 Mi<=5,T<=20;
    对于 60%的数据,n<=100,所有的 Mi<=100,T<=2000;
    对于 100%的数据,n<=500,所有的 Mi<=500,T<=500000,所有的 0<C<=10^9,并保证最终解 Max<=10^9。

    正解:DP

    解题报告:

      这道题我开始居然想了很久,我真是太菜了。。。

      果断DP,每个人的各段区间没有任何区别,直接丢一起按照左端点排序。题目可转化为给定若干带权区间,取出不重叠的区间使权值最大。

      貌似大家都是在做区间数的做法。。。我是直接讨论时间,for时间,然后记录一下处理到哪段区间,并且当前的最左端点,一维DP

     1 //It is made by jump~
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <algorithm>
     8 #include <ctime>
     9 #include <vector>
    10 #include <queue>
    11 #include <map>
    12 #include <set>
    13 #ifdef WIN32   
    14 #define OT "%I64d"
    15 #else
    16 #define OT "%lld"
    17 #endif
    18 using namespace std;
    19 typedef long long LL;
    20 const int MAXN = 511;
    21 const int MAXT = 500011;
    22 int n,tim;
    23 int m[MAXN];
    24 int cnt;
    25 int f[MAXT];//f[i]表示i时刻(含)之前的最大值
    26 
    27 struct seq{
    28     int l,r,val;
    29 }a[MAXN*MAXN],jump[MAXN*MAXN];
    30 
    31 inline int getint()
    32 {
    33        int w=0,q=0;
    34        char c=getchar();
    35        while((c<'0' || c>'9') && c!='-') c=getchar();
    36        if (c=='-')  q=1, c=getchar();
    37        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
    38        return q ? -w : w;
    39 }
    40 
    41 inline bool cmp(seq q,seq qq){ if(q.l==qq.l) return q.r<qq.r;  return q.l<qq.l;   }
    42 
    43 int main()
    44 {
    45   n=getint(); tim=getint();
    46   for(int i=1;i<=n;i++) {
    47       m[i]=getint();
    48       for(int j=1;j<=m[i];j++) {
    49       a[++cnt].l=getint();
    50       a[cnt].r=getint();
    51       a[cnt].val=getint();
    52       }
    53   }
    54 
    55   sort(a+1,a+cnt+1,cmp);
    56 
    57   int ji=1,nowl=a[1].l;
    58   //f[a[1].r]=a[1].val;
    59   for(int i=1;i<=tim;i++) {
    60       f[i]=max(f[i-1],f[i]);
    61       if(i<nowl) continue;
    62       while(a[ji].l==nowl && ji<=cnt) f[a[ji].r]=max(f[a[ji].r],f[i-1]+a[ji].val),ji++;
    63       nowl=a[ji].l;
    64   }
    65 
    66   printf("%d",f[tim]);
    67   return 0;
    68 }


    3、集合(gather)
    【问题描述】
    小明总喜欢做一些与众不同的事情,最近他迷上了集合运算。他觉得光是简单的预算不过瘾,所以他把2个集合运算集合起来。由于小明很喜欢区间运算。于是他定义了一个这样的值。
    你N个各不相同的区间,请你从中找出若干个区间使其权值最大。
    W=|A1∪A2∪……∪AK|*|A1∩A2∩……AK|
    其中{A1,A2……AK}(K>1,Ai<>Aj{i<>j})
    如果这些区间没有交集则权值为0,给你N个各不相同的区间,请你从中找出若干个区间使其权值最大,并告诉小明。
    【输入文件】
    第一行N
    接下来N行 l r(1<=l<r<=10^6)
    【输出文件】
    最大权值
    【输入样例】
    4
    1 6
    4 8
    2 7
    3 5
    【输出样例】
    24
    【数据约定】
    10% N<=10
    30% N<=2*10^4
    50% N<=10^5
    100% 1<N<=10^6

    正解:决策单调性

    解题报告:

      考场上明明想出来了,一定是两个的时候最优,但是自己不相信自己,而且感觉n^2的暴力也会TLE就没打,打了一个大暴力,水到20分。

      等我打完大暴力,心血来潮make数据发现永远是2个的时候最优。。。追悔莫及。。。

      显然直接两两枚举会TLE,就要考虑优化。

      题解说 用决策单调性,有一些奇奇怪怪的性质。传送门:http://www.cnblogs.com/chenyushuo/p/5261657.html

      这道题居然是BZOJ原题,出题人真懒。

      先贴一发大暴力:

      1 //It is made by jump~
      2 #include <iostream>
      3 #include <cstdlib>
      4 #include <cstring>
      5 #include <cstdio>
      6 #include <cmath>
      7 #include <algorithm>
      8 #include <ctime>
      9 #include <vector>
     10 #include <queue>
     11 #include <map>
     12 #include <set>
     13 #ifdef WIN32   
     14 #define OT "%I64d"
     15 #else
     16 #define OT "%lld"
     17 #endif
     18 using namespace std;
     19 typedef long long LL;
     20 const int MAXN = 1000011;
     21 int n;
     22 bool pd[MAXN];
     23 int ans;
     24 
     25 struct seq{
     26     int l,r;
     27 }a[MAXN],dui[MAXN];
     28 
     29 inline int getint()
     30 {
     31        int w=0,q=0;
     32        char c=getchar();
     33        while((c<'0' || c>'9') && c!='-') c=getchar();
     34        if (c=='-')  q=1, c=getchar();
     35        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
     36        return q ? -w : w;
     37 }
     38 
     39 inline bool cmp(seq q,seq qq){
     40     if(q.l==qq.l) return q.r<qq.r;
     41     return q.l<qq.l;
     42 }
     43 
     44 inline void check(int cnt){
     45     if(cnt==0 || cnt==1) return ;
     46     int total=0;
     47     for(int i=1;i<=n;i++) if(pd[i]) dui[++total]=a[i];
     48     sort(dui+1,dui+total+1,cmp);
     49     int head=dui[1].l,tail=dui[1].r;
     50     int maxl=0;
     51     for(int i=1;i<=total;i++) head=max(head,dui[i].l),tail=min(tail,dui[i].r);
     52     if(head>=tail) return;
     53     maxl=tail-head;
     54 
     55     int nowl=dui[1].l,nowr=dui[1].r;
     56     int ji=0; ji=nowr-nowl;
     57     for(int i=2;i<=total;i++) {
     58     if(dui[i].l==nowl) ji+=dui[i].r-nowr,nowr=dui[i].r;
     59     else{ 
     60         nowl=dui[i].l; 
     61         if(nowl>nowr)  {
     62         ji+=dui[i].r-dui[i].l; 
     63         nowr=dui[i].r;
     64         }
     65         else{
     66         if(dui[i].r>nowr) {
     67             ji+=dui[i].r-nowr;
     68             nowr=dui[i].r;
     69         }
     70         }
     71     }
     72     }
     73     maxl*=ji;
     74     if(maxl>ans) {
     75     ans=maxl;
     76     /*for(int i=1;i<=n;i++)
     77         if(pd[i])
     78         printf("%d ",i);
     79         printf("
    %d 
    ",ans);*/
     80     }
     81 }
     82 
     83 inline void dfs(int now,int cnt){
     84     if(now==n+1) {  check(cnt);return ; }
     85     pd[now]=1; dfs(now+1,cnt+1);
     86     pd[now]=0; dfs(now+1,cnt);
     87 }
     88 
     89 inline void solve(){
     90   n=getint();
     91   for(int i=1;i<=n;i++) a[i].l=getint(),a[i].r=getint();
     92 
     93   dfs(1,0);
     94 
     95   printf("%d",ans);
     96 }
     97 
     98 int main()
     99 {
    100   solve();
    101   return 0;
    102 }

    正解:单调队列+单调栈

      1 //It is made by jump~
      2 #include <iostream>
      3 #include <cstdlib>
      4 #include <cstring>
      5 #include <cstdio>
      6 #include <cmath>
      7 #include <algorithm>
      8 #include <ctime>
      9 #include <vector>
     10 #include <queue>
     11 #include <map>
     12 #include <set>
     13 #ifdef WIN32   
     14 #define OT "%I64d"
     15 #else
     16 #define OT "%lld"
     17 #endif
     18 using namespace std;
     19 typedef long long LL;
     20 const int MAXN = 1000011;
     21 int n,cnt;
     22 LL ans;
     23 
     24 struct seq{
     25     int l,r;
     26 }a[MAXN];
     27 
     28 inline LL calc(const seq &j,const seq &i){return 1LL*(i.r-j.l)*(j.r-i.l);}
     29 
     30 inline int getint()
     31 {
     32        int w=0,q=0;
     33        char c=getchar();
     34        while((c<'0' || c>'9') && c!='-') c=getchar();
     35        if (c=='-')  q=1, c=getchar();
     36        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
     37        return q ? -w : w;
     38 }
     39 
     40 inline bool cmp(seq q,seq qq){
     41     if(q.l==qq.l) return q.r>qq.r;
     42     return q.l<qq.l;
     43 }
     44 
     45 inline LL max(LL pp,LL ppp){ if(pp<ppp) return ppp; return pp; }
     46 
     47 struct stac{
     48     int pos,top;
     49     struct data{
     50     int l,r,id;
     51     }lin,sta[MAXN];
     52     inline void init(){ sta[top=1]=(data){2,n,1}; pos=1; }
     53     bool comp(int xx,int x,int y){return calc(a[x],a[xx])<calc(a[y],a[xx]);}
     54     inline int get(int id){
     55     int l=lin.l,r=lin.r,bian=lin.id;
     56     int mid;
     57     while(l<r) {
     58         mid=(l+r)/2+1;
     59         if(comp(mid,bian,id)) l=mid; else r=mid-1;
     60     }
     61     return l;
     62     }
     63     inline void push(int id){
     64     while(top && !comp(sta[top].l,sta[top].id,id)) top--;
     65     lin=sta[top--];
     66     int m=get(id);
     67     if(lin.l<=m) sta[++top]=(data){lin.l,m,lin.id};
     68     if(m<n) sta[++top]=(data){m+1,n,id};
     69     }
     70     inline LL query(int x){
     71     while(x>sta[pos].r) pos++;
     72     return calc(a[sta[pos].id],a[x]);
     73     }
     74 }stack;
     75 
     76 struct queue{//单调队列,维护一个左端点、右端点坐标都单调递增,长度单调递减的区间队列
     77     int head,tail;
     78     struct data{
     79     int r,len;
     80     }seq[MAXN],lin;
     81     inline void push(int id){
     82     lin=(data){a[id].r,a[id].r-a[id].l};
     83     while(head<=tail && seq[tail].len<=lin.len) tail--;
     84     seq[++tail]=lin;
     85     }
     86     inline LL query(int id){
     87     int r=a[id].r;
     88     while(head<=tail && seq[head].r<r) head++;
     89     if(head<=tail) return seq[head].len;
     90     else return -1;
     91     }
     92 }que;
     93 
     94 inline void solve(){
     95     n=getint();
     96     for(int i=1;i<=n;i++) a[i].l=getint(),a[i].r=getint();
     97 
     98     sort(a+1,a+n+1,cmp);
     99     int last=0;
    100     que.head=1;
    101     for(int i=1;i<=n;i++) {
    102     if(a[i].r>last) last=a[i].r,a[++cnt]=a[i],que.push(i);//得到去掉互相包含之后的新区间集,并加入单调队列,更新当前最右的端点值
    103     else ans=max( que.query(i)*(a[i].r-a[i].l) , ans );//计算互相包含的情况
    104     }
    105 
    106     stack.init();
    107     for(int i=2;i<=cnt;i++) {
    108     ans=max(ans,stack.query(i)),stack.push(i);
    109     }
    110 
    111     printf(OT,ans);
    112 }
    113 
    114 int main()
    115 {
    116   solve();
    117   return 0;
    118 }


    4、新斯诺克(snooker.cpp/c/pas)
    【问题描述】
    斯诺克又称英式台球,是一种流行的台球运动。在球桌上,台面四角以及两长边中心位置各有一个球洞,使用的球分别为 1 个白球,15 个红球和 6 个彩球(黄、绿、棕、蓝、粉红、黑)共22个球。击球顺序为一个红球、一个彩球直到红球全部落袋,然后以黄、绿、棕、蓝、粉红、黑的顺序逐个击球,最后以得分高者为胜。斯诺克的魅力还在于可以打防守球, 可以制造一些障碍球使对方无法击打目标球而被扣分。正是因为这样,斯诺克是一项充满神奇的运动。 现在考虑这样一种新斯诺克,设母球(母球即是白球,用于击打其他球)的标号为M,台面上有 N 个红球排成一排,每一个红球都有一个标号,`他们的标号代表了他们的分数。 现在用母球击打这些红球,一杆击打,如果母球接触到红球,就称为“K 到红球”。我们假设,一次可以击打任意多相邻连续的红球,也可以只击打一个球。并且红球既不会落袋,也不会相互发生碰撞,而只是停留在原处。每次击打时候,要想“K到红球”,至少要击打一个红球,如果想一次击打多个红球,那么击打的红球必须是依次连续排列的。 如果一次 “K 到红球”所有红球的标号之和的平均数大于母球的标号M,就获得了一个 “连击”。 现在请你计算总共能有多少种“连击”方案。
    注意:如果当前有标号为 1、2、3的三种红球,母球标号为 0, 有如下 6 种获得“连击”方案: (1) 、 (2) 、 (3) 、 (1,2) 、 (2,3) 、 (1,2,3)
    【输入文件】
    输入文件共有两行,第一行是 N,M (N<=100000,M<=10000),
    N 表示台面上一共有 N 个红球,M 表示母球的标号。
    第二行是 N 个正整数,依次表示台面上 N 个红球的标号,所有标号均不超过10000。
    【输出文件】
    输出文件只有一个数,为“连击”的方案总数。
    【输入样例】
    4 3
    3 7 2 4
    【输出样例】
    7

    正解:归并排序,逆序对 

    解题报告:

      刚看到这道题就想到POJ上刷的那道求序列的最大平均值的神题,那个是用斜率优化、凸包优化的DP,结果发现跟这道题并没有关系,被小胖犇狠狠嘲讽了一波。

      静下心来推导了一波。发现一个神奇的性质:一个区间[i,j]满足条件当且仅当(前缀和)(sum[j]-sum[i-1])/(j-i) > m,移项:(sum[j]-sum[i-1])>(j-i)*m。。。高兴地发现这就是一个逆序对。。。

      直接归并排序,求前缀和的逆序对。

     1 //It is made by jump~
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <algorithm>
     8 #include <ctime>
     9 #include <vector>
    10 #include <queue>
    11 #include <map>
    12 #include <set>
    13 #ifdef WIN32   
    14 #define OT "%I64d"
    15 #else
    16 #define OT "%lld"
    17 #endif
    18 using namespace std;
    19 typedef long long LL;
    20 const int MAXN = 100011;
    21 int n,m;
    22 int sum[MAXN],a[MAXN],jump[MAXN];
    23 int g[MAXN];
    24 LL ans;
    25 
    26 inline int getint()
    27 {
    28        int w=0,q=0;
    29        char c=getchar();
    30        while((c<'0' || c>'9') && c!='-') c=getchar();
    31        if (c=='-')  q=1, c=getchar();
    32        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
    33        return q ? -w : w;
    34 }
    35 
    36 inline void merge(int l,int mid,int r){
    37     int i=l,j=mid+1;
    38     int cnt=l;
    39     while(i<=mid && j<=r) {
    40     if(jump[i]<=jump[j])  g[cnt++]=jump[i++];
    41     else{
    42         g[cnt++]=jump[j++];
    43         //ans+=mid-i+1;
    44         ans+=(LL)mid; ans-=(LL)i; ans++;
    45     }
    46     }
    47     while(i<=mid) g[cnt++]=jump[i++];
    48     while(j<=r) g[cnt++]=jump[j++];
    49     //for(;i<=mid;i++) g[cnt++]=a[i];
    50     //for(;j<=r;j++) g[cnt++]=a[i];
    51     for(i=l;i<=r;i++) jump[i]=g[i];
    52 }
    53 
    54 inline void gui(int l,int r){
    55     if(l==r) return ;
    56     int mid=(l+r)/2;
    57     gui(l,mid); gui(mid+1,r);
    58     merge(l,mid,r);
    59 }
    60 
    61 inline void solve(){
    62     n=getint();m=getint();
    63     for(int i=1;i<=n;i++) {
    64     a[i]=getint(); sum[i]=sum[i-1]+a[i];
    65     jump[i]=sum[i]-m*i;
    66     }
    67     for(int i=1;i<=n;i++) jump[i]=-jump[i];//正序对变成逆序对
    68 
    69     gui(0,n);
    70     
    71     printf(OT,ans);
    72 }
    73 
    74 int main()
    75 {
    76   solve();
    77   return 0;
    78 }
  • 相关阅读:
    个人常用Git操作记录
    JavaScript引擎基本原理:Shapes和Inline Caches
    Promise.then(a, b)与Promise.then(a).catch(b)问题详解
    p标签中的文本换行
    Vue初始化
    关于vue的源码调试
    关于extjs表单布局的几种方式
    sublime text3安装、注册及常用插件
    chrome扩展程序开发
    关于Git的简单使用
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5573620.html
Copyright © 2020-2023  润新知