山东冬令营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<=200000,0<=|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 } 

  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 }

  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 } 

原文地址:https://www.cnblogs.com/yuelian/p/8946791.html

时间: 2024-10-31 09:26:59

山东冬令营2018:贪心专练的相关文章

2018.10.10 练习赛 状态压缩专练

T1 防守马克 题解: 贪心,用(力量+重量)排序然后\(dfs\); \(code\): #include<iostream> #include<cstdio> #include<algorithm> using namespace std; struct node{ int h,w,s; }a[30]; int n,h; bool c[30]; long long ans=-1; bool cmp(const node &x,const node &

道路重建 (2018山东冬令营)

问题 C: 道路重建 时间限制: 1 Sec  内存限制: 128 MB提交: 67  解决: 24[提交][状态][讨论版] 题目描述 小L的家乡最近遭遇了一场洪水,城市变得面目全非,道路也都被冲毁了.生活还要继续,于是市政府决定重建城市中的道路. 在洪水到来前,城市中共有n个区域和m条连接这些区域的双向道路, 道路连通了所有的区域,为了方便人们的出行,只能重建这些原有的道路, 不能建新的道路.编号为s的区域是市政广场,市政府希望重建的道路能够 使得所有区域到市政广场的最短路与受灾前保持不变,

2018.10.10 练习赛 状态压缩专练(T4-T5)

T4 Tourism 题解: \(F[p][s]\)表示讨论到p号点,根到p路径(不包含p)上的点的服务状态为s的最小费用. \(S\)是\(3\)进制数,\(0\)表示\(p\)自己服务自己,\(1\)表示\(p\)没有被服务到,\(2\)表示被其它点服务,这里的状态记录的是父亲 一直到根这条链上的,不超过\(10\)层,所以最多是\(3^{10}\) \(code\): //待补 T2 LED 题解: 待补 \(code:\) //待补 原文地址:https://www.cnblogs.co

2018.10.15 练习赛 搜索专练

T1 乘积分解 题解: 预处理出\(n\)的约数,用\(F[i][j]\)记录从排序后的第i个因数出发,连续\(j\)个因数的乘积. 要求\(fFi][j]<=n\),且\(j<=k\) \(code\): #include<cstdio> #include<algorithm> #include<iostream> #include<ctype.h> #include<ctime> #define ll long long usin

2018.10.18 练习赛 数学专练

T1 打气球 题解: 期望递推,不关心具体位置,所以\(F[i][j]\)表示还有\(i\),\(j\)行,列未完; \(code\): #include<cstdio> #include<algorithm> #include<ctype.h> #include<vector> #include<queue> #include<cstring> #define lowbit(x) (x&-x) #define ll long

2016.4.3 动态规划NOI专练 王老师讲课整理

1.6049:买书 总时间限制:  1000ms 内存限制:  65536kB 描述 小明手里有n元钱全部用来买书,书的价格为10元,20元,50元,100元. 问小明有多少种买书方案?(每种书可购买多本) 输入 一个整数 n,代表总共钱数.(0 <= n <= 1000) 输出 一个整数,代表选择方案种数 样例输入 样例输入1: 20 样例输入2: 15 样例输入3: 0 样例输出          样例输出1:           2         样例输出2:       0    

[网络流专练5][圆桌问题]

题目描述 “假设有来自n 个不同单位的代表参加一次国际会议.每个单位的代表数分别为 ri i=1,2,……n .会议餐厅共有 m张餐桌,每张餐桌可容纳ci i=1,2, ……,m 个代表就餐. 为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐.试设计一个算法, 给出满足要求的代表就餐方案.” Solution 少了套路,多了真诚 1.套路 当然是对题目中敏感的对象建点 考虑对单位和餐桌建点,而不是个人建点(很容易走偏的思路) 2.算法 那么,很容易想出连边(任意单位i,任意餐桌j

2016.4.9 NOI codevs动态规划专练

1.NOI 最大子矩阵 1:最大子矩阵 总时间限制:  1000ms 内存限制:  65536kB 描述 已知矩阵的大小定义为矩阵中所有元素的和.给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵. 比如,如下4 * 4的矩阵 0 -2 -7 09 2 -6 2-4 1 -4 1-1 8 0 -2 的最大子矩阵是 9 2-4 1-1 8 这个子矩阵的大小是15. 输入 输入是一个N * N的矩阵.输入的第一行给出N (0 < N <= 100).再后面的若干行中,依次(首先从

[网络流专练6][线性规划与网络流剩余部分题解]

orz"orzGEOTCBRL" 6:lis 给定正整数序列x1 ,…… , xn. (1)计算其最长递增子序列的长度s. (2)计算从给定的序列中最多可取出多少个长度为s的递增子序列. (3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长 度为s的递增子序列.  看到题目就666了,前两问不是经典dp?因为序列是上升的,所以如果在x1前面加一个x1,个数显然多了f[x2][xn][s-1],或者xn后面加一个xn, 一样的……然后发现题意理解错T_T “多