• 山东冬令营2018:贪心专练


      T1:

    数轴上有 n 个点,第 i 个点的坐标为 xi,权值为 wi。两个点 i,j 之间存在一条边当且仅当 abs(xi-xj)>=wi+wj。
    你需要求出这张图的最大团的点数。
    (团就是两两之间有边的顶点集合)
    【输入格式】
    输入文件clique.in
    第一行一个整数 n,接下来 n 行每行两个整数 xi,wi。
    【输出格式】
    输出文件clique.out
    输出一行一个整数,表示最大团的点数。
    【样例输入】
    4
    2 3
    3 1
    6 1
    0 2
    【样例输出】
    3
    【数据范围】
    对于 20%的数据,n<=10。
    对于 60%的数据,n<=1000。
    对于 100%的数据,n<=2000000<=|xi|,wi<=10^9

      本弱看到这道题时第一反应肯定是n^2连边也过不了啊,所以肯定有巧妙的方法来解这道题废话我们可以看到,有边相连的2个点的要求是abs(xi-xj)>=wi+wj,也就是说如果i和j有边,那么从xi-wi到xi+wi和xj-wj到xj+wj这两段区间是没有重合部分的,那么我们把每个点都扩成一段区间,最多的不重合的区间数就是最大团的点数,因为互不重合就代表了两两之间有边。

    代码:

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstdio>
     4 using namespace std;
     5 const int maxn=200004;
     6 int n;
     7 struct zhw{
     8     int l,r;
     9     friend bool operator <(zhw a,zhw b)
    10     {
    11         return  a.r<b.r||(a.r==b.r&&a.l>b.l);
    12     }
    13 }a[maxn];
    14 int x,w,l,r;
    15 int main()
    16 {
    17     freopen("clique.in","r",stdin);
    18     freopen("clique.out","w",stdout);
    19     scanf("%d",&n);
    20     for(int i=1;i<=n;++i)
    21     {
    22         scanf("%d%d",&x,&w);
    23         a[i].l=x-w,a[i].r=x+w;
    24     }
    25     sort(a+1,a+n+1);
    26     int pos=a[1].r,ans=1;
    27     for(int i=1;i<=n;++i)
    28     {
    29         if(a[i].l>=pos)ans++,pos=a[i].r;
    30     }
    31     printf("%d",ans);
    32     fclose(stdin);fclose(stdout);
    33     return 0;
    34 } 
    View Code

      T2:

    小 H 参加了一场神秘的游戏。游戏中有 n 堆硬币,第 i 堆价值 ai。
    每次小 H 可以选择编号相差 k 的硬币同时拿走。注意拿走后硬币不进行重标号。
    小 H 想知道最多能拿走多大价值的硬币。
    【输入格式】
    输入文件coin.in
    第一行两个整数 n,k。
    第二行 n 个整数。第 i 个整数表示 ai。
    【输出格式】
    输出文件coin.out
    一行一个整数,表示拿走硬币的最大价值。
    【样例输入】
    7 3
    7 5 8 6 4 3 2
    【样例输出】
    33
    【数据范围】
    对于 20%的数据,n<=20。
    对于 40%的数据,n<=2000。
    对于另外 20%的数据,k<=10。
    对于 100%的数据,n<=100000,k<=n,0<=ai<=1000000000

      本弱的脑回路有点怪(其实就是弱的做不粗来),想了半天的给可以同时拿走的数之间连边,也没搞出来,最后去看的题解(捂脸)。思路如下:既然可以两组队的拿走,那么对于膜k相等的数里就最多只有1个数拿不走,就是当这些数有奇数个的时候,有一个拿不走,并且这个一定是在奇数位置的,就是把所有的膜k相等的数按原来的顺序排成一列,奇数位置上的数,所以只要把这些位置上的数取min,然后把这个最小的数减掉就可以了,不过如果一共有偶数个就不需要减了,因为都可以拿走。

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 const int maxn=100003;
     5 long long a[maxn];
     6 int n,k;
     7 long long ans;
     8 int main()// 
     9 {
    10 //    freopen("coin.in","r",stdin);
    11 //    freopen("coin.out","w",stdout);
    12     scanf("%d%d",&n,&k);
    13     for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
    14     for(int i=1;i<=k;++i)
    15     {
    16         int tot=0,Min=2147483640;//极大值开小了 
    17         for(int j=i;j<=n;j+=k)
    18         {
    19             tot^=1,ans+=a[j];
    20             if(tot)Min=Min>a[j]?a[j]:Min;
    21         }
    22         ans-=tot*Min;
    23     }
    24     printf("%lld",ans);
    25     return 0;
    26 }
    View Code

      T3:

    有n个樱桃排成一列,第i个樱桃的甜度为v[i],你要把n个樱桃分成若干组,其中每一组的樱桃必须相邻。每一组樱桃的美味度为(sum-T)^2 , 其中sum是这组樱桃的甜度之和,T为输入给定的系数。
    一组方案的美味度为每一组的美味度之和。
    求可行方案最小的美味度。
    【输入格式】
    输入文件cherry.in
    第一行两个正整数 n,T。
    第二行n个整数,第i个整数是第i个樱桃的甜度,v[i]。
    【输出格式】
    输出文件cherry.out
    一行一个非负整数,为最小美味度。
    【样例输入】
    5 5
    3 5 2 1 6
    【样例输出】
    9
    【数据范围】
    对于50%的数据满足 n<=10,T<=1000,v[i]<=10
    对于70%的数据满足 n<=100
    对于所有数据,n<=10^3,T<=1000,v[i]<=10

      看到数据范围肯定会想起是不是n^2做法啊,其实这题大概是dp,f[i]代表前i个樱桃分成若干组的最小美味度,那么有转移方程:f[i]={min(f[i],sum[i]-sum[j-1]-T)^2) | j<=i},然后就皆大欢喜啦。

    代码:

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 using namespace std;
     5 const int maxn=1005;
     6 int n,t;
     7 int v[maxn],sum[maxn];
     8 int f[maxn];
     9 int main()
    10 {
    11 //    freopen("cherry.in","r",stdin);
    12 //    freopen("cherry.out","w",stdout);
    13     scanf("%d%d",&n,&t);
    14     for(int i=1;i<=n;++i)scanf("%d",&v[i]),sum[i]=sum[i-1]+v[i];
    15     memset(f,127/3,sizeof(f));
    16     f[0]=0;
    17     for(int i=1;i<=n;++i)
    18         for(int j=1;j<=i;j++)
    19             f[i]=min(f[i],f[j-1]+(sum[i]-sum[j-1]-t)*(sum[i]-sum[j-1]-t));
    20     printf("%d",f[n]);
    21     return 0;        
    22 } 
    View Code
  • 相关阅读:
    shell 函数
    PHP curl 实现RESTful PUT DELETE 实例
    call_user_func_array
    Laravel 文档中的 Service Providers
    window7主题破解与恢复(复制)
    ORM到底是用还是不用?(复制)
    关于cgi、FastCGI、php-fpm、php-cgi(复制)
    C语言赋初始值
    MySQL临时表的简单用法(复制)
    Mysql Having的用法:对group by之后的分组加限制条件(复制)
  • 原文地址:https://www.cnblogs.com/yuelian/p/8946791.html
Copyright © 2020-2023  润新知