贪心

CFB. New Year and the Treasure Geolocation贪心!

 

 

这题...直接把前n行的最大的pair
加上后n行里最小的pair即可
因为最后是要归于同一个点

 

Codeforces 1028C rectangles

 

 

 给定n个矩形,寻找其中n-1个矩形重合得到的最大矩形

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define int long long
 4 #define inf 1e9
 5 const int N = 132675;
 6 int a[N], b[N], c[N], d[N], x[N], y[N], xx[N], yy[N];
 7 int32_t main(){
 8 
 9     int n;
10     cin >> n;
11     for (int i = 0; i < n;i++){
12         cin >> a[i] >> b[i] >> c[i] >> d[i];
13         x[i] = a[i];
14         y[i] = b[i];
15         xx[i] = c[i];
16         yy[i] = d[i];
17     }
18     sort(x, x + n);
19     sort(y, y + n);
20     sort(xx, xx + n);
21     sort(yy, yy + n);
22 
23     for (int i = 0; i < n;i++){
24         int x1 = x[n - 1];
25         int y1 = y[n - 1];
26         int xx1 = xx[0];
27         int yy1 = yy[0];
28         if(a[i]==x[n-1])
29             x1 = x[n - 2];
30         if(b[i]==y[n-1])
31             y1 = y[n - 2];
32         if(c[i]==xx[0])
33             xx1 = xx[1];
34         if(d[i]==yy[0])
35             yy1 = yy[1];
36         if(x1<=xx1&&y1<=yy1)
37         {
38             cout << x1 << " " << y1;
39             //system("pause");
40             return 0;
41         }
42     }
43     return 0;
44 }

反对所有前缀和/线段树/---/的做法,排序+贪心就可以了,没有必要那么麻烦

 

 

 三种方法,自己比较一下,就知道哪种更好了

WAY1:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define int long long
 4 #define s second
 5 #define f first
 6 const int N = 1e6;
 7 const int INF = 1e9;
 8 int ans = 0;
 9 pair<int,int> a[N], pre[N], suf[N];//prefix前缀,suffix后缀
10 int32_t main(){
11     ios_base::sync_with_stdio(0);
12     cin.tie(0);
13     int n;cin>>n;
14     for(int i=1;i<=n;i++)
15         cin>>a[i].f>>a[i].s;
16 
17     pre[0].f=suf[n+1].f=0;//等会用于比大小的
18     pre[0].s=suf[n+1].s=INF;//等会用于比大小的
19     for(int i=1;i<=n;i++){
20         pre[i].f=max(pre[i-1].f,a[i].f);//表示前i个数中,最大的左端点的坐标
21         pre[i].s=min(pre[i-1].s,a[i].s);//表示前i个数中,最小的右端点的坐标
22     }
23     for(int i=n;i>=1;i--){
24         suf[i].f=max(suf[i+1].f,a[i].f);//表示从第i个数到第n个数中,最大的左端点的坐标
25         suf[i].s=min(suf[i+1].s,a[i].s);//表示从第i个数到第n个数中,最小的右端点的坐标
26     }
27     for(int i=1;i<=n;i++){
28         int l=max(pre[i-1].f,suf[i+1].f);//除去第i个线段后,最大的左端点的坐标
29         int r=min(pre[i-1].s,suf[i+1].s);//除去第i个线段后,最小的右端点的坐标
30         ans = max(ans, r - l);
31         }
32     cout << ans;
33     //system("pause");
34     return 0;
35 }

WAY2:

 1  #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N = 3e5 + 10;
 4 const int INF = int(1e9);
 5 #define int long long
 6 multiset<int>a, b;
 7 int n, l[N], r[N],ans,ans1;
 8 int32_t main(){
 9     cin >> n;
10     for(int i=0;i<n;i++){
11         cin >>l[i] >> r[i];
12         a.insert(l[i]);
13         b.insert(r[i]);
14     }
15     for (int i = 0; i < n;i++){
16         a.erase(a.find(l[i]));
17         b.erase(b.find(r[i]));
18         ans = max(ans, *b.begin() - *a.rbegin());
19         a.insert(l[i]);
20         b.insert(r[i]);
21     }
22     
23     cout << ans;
24 
25     //system("pause");
26     return 0;
27 }

WAY1和WAY2的思想是一样的

 

WAY3:和上一题是一个意思,一个是一维的,一个是二维的,显然第三种更好。

 

 

 

 

 

 

Kruskal算法

贪心策略:n个节点的最小生成树里面包含了n-1条边,这n-1条边是不可以成环的,这样就可以保证联通了,所以我们只要把这n-1条边选出来,因为是最小生成树,所以我们要找最小的权边

基本的思路:

  存边

  按照权值将这些边排序

  排序完了开始遍历,决定把谁加入MST

  判断的条件是:是否成环,成环的话就不要,不成环的话就加入MST

  接下来要解决的问题就是怎么判断成环->利用并查集,共祖->成环

  共祖在某种意义上就等于联通

  所以有一个查的过程和并的过程

 代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=5020;
 5 const int F = 2e5 + 100;
 6 struct node{
 7     int u, v, c; 8 } e[F]; 9 int f[N],cnt,sum; 10 int find(int x){ 11 return f[x] == x ? x : f[x] = find(f[x]);} 12 bool unionset(int a,int b){ 13 a = find(a),b = find(b); 14 if(a!=b){ 15 f[b] = a; 16 return true; 17  } 18 return false; 19 } 20 bool cmp(node a,node b){ 21 return a.c < b.c; 22 } 23 int main(){ 24 int n, m; 25 scanf("%d%d", &n, &m); 26 for (int i = 1; i <=m;i++){ 27 scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].c); 28  } 29 sort(e + 1, e + 1 + m, cmp); 30 for (int i = 1; i <= n;i++) 31 f[i] = i;//并查集的初始化 32 for (int i = 1; i <= m;i++){ 33 if(unionset(e[i].u,e[i].v)){ 34 cnt++; 35 sum += e[i].c; 36  } 37 if(cnt==n-1) 38 break; 39  } 40 printf("%d",sum); 41 //system("pause"); 42 return 0; 43 }

 

 

 

浙大校赛

ZOJ3953 intervals

过这题的人很少,但其实是一道贪心题

 ternary search

这是这个贪心里需要注意的,这个三元搜索和平时说的三分搜索不一样

这个词是在codeforces global 2的E题的tag里看见的,同样是一道贪心。

要求给定区域内,不存在大于等于三个区间重合

“区间贪心”

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define int long long
 4 #define scan(n) scanf("%lld", &n);
 5 struct node{
 6     int l, r,id;
 7 } a[50020],t[5];
 8 bool cmp(node a,node b){
 9     if(a.l==b.l)
10         return a.r < b.r;
11     return a.l < b.l;
12 }
13 bool cmp2(node a,node b){
14     return a.r > b.r;
15 }
16 int ans[50020],n;
17 int32_t main(){
18     int T;
19     scan(T);
20     while(T--){
21         scan(n);
22         for (int i = 1; i <= n;i++){
23             scanf("%lld%lld", &a[i].l, &a[i].r);
24             a[i].id = i;
25         }
26         sort(a + 1, a + 1 + n, cmp);
27         int cnt = 0;
28         t[1] = a[1];
29         t[2] = a[2];
30         for (int i = 3; i <= n;i++){
31             t[3] = a[i];
32             sort(t + 1, t + 4, cmp);
33             if(t[1].r>=t[2].l&&t[2].r>=t[3].l&&t[1].r>=t[3].l){//重合
34                 sort(t+1, t + 4, cmp2);
35                 ans[cnt++] = t[1].id;
36                 swap(t[1], t[3]);
37             }
38             else
39                 sort(t + 1, t + 4, cmp2);
40         }
41         sort(ans, ans + cnt);
42         printf("%lld\n", cnt);
43         for (int i = 0; i < cnt;i++){
44             printf("%lld ", ans[i]);
45         }
46     }
47     //system("pause");
48 }

 

 

贪心与动态规划的结合

这是在浙大校赛中遇到的两道题目,都是01背包,但是融入了贪心的思想

 

 对于01背包,存在“选”与“不选”两个状态,那么选择的顺序呢?

分析这道题目的条件就会发现,需要一个简单的排序。这样计算的时候,物品体积就是排序后体积的前缀和

并且这道题目,由于有两个k值,所以定义一个二维dp数组,表示选取k1数组的前i个和k2数组的前j个

 

 ZOJ3958

 

 这题也是一样

 观察数据,发现,Ci<=100,啊哈哈哈哈

所以Ci的和相同时,只需要看Hi的和的大小,明确了这点,小书包背上~

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define int long long
 4 int h[600], c[600], dp[50020];
 5 int n, ans, sum;
 6 int32_t main()
 7 {
 8     int T;cin>>T;
 9     while(T--){
10         sum = 0, ans = 0;
11         scanf("%lld", &n);
12         memset(dp, 0, sizeof(dp));
13         for (int i = 1; i <= n;i++){
14             scanf("%lld%lld", &h[i], &c[i]);
15             sum += c[i];
16         }
17         //initially select all of them;
18         for (int i = 1; i <=n;i++){
19             for (int j = sum; j >= c[i];j--){
20                 dp[j] = max(dp[j], dp[j - c[i]] + h[i]);
21             }
22         }
23         for (int i = 1; i <= sum;i++){
24             ans = max(dp[i] * dp[i] - i * dp[i] - i * i, ans);
25         }
26         printf("%lld\n", ans);
27     }
28     //system("pause");
29     return 0;
30 }

 

 

E. Pavel and Triangles

Pavel has several sticks with lengths equal to powers of two.

He has a0a0 sticks of length 20=120=1, a1a1 sticks of length 21=221=2, ..., an1an−1 sticks of length 2n12n−1.

Pavel wants to make the maximum possible number of triangles using these sticks. The triangles should have strictly positive area, each stick can be used in at most one triangle.

It is forbidden to break sticks, and each triangle should consist of exactly three sticks.

Find the maximum possible number of triangles.

Input

The first line contains a single integer nn (1n3000001≤n≤300000) — the number of different lengths of sticks.

The second line contains nn integers a0a0, a1a1, ..., an1an−1 (1ai1091≤ai≤109), where aiai is the number of sticks with the length equal to 2i2i.

Output

Print a single integer — the maximum possible number of non-degenerate triangles that Pavel can make.

Examples
input
Copy
5
1 2 2 2 2
output
Copy
3
input
Copy
3
1 1 1
output
Copy
0
input
Copy
3
3 3 3
output
Copy
3
 
 
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define int long long
 4 #define sys system("pause")
 5 #define scan(n) scanf("%I64d", &(n))
 6 #define scann(n, m) scanf("%I64d%I64d", &(n), &(m))
 7 #define prin(n) printf("%I64d", (n))
 8 #define scannn(a,b,c) scanf("%I64d%I64d%I64d",&(a),&(b),&(c))
 9 #define ff first
10 #define ss second
11 #define mp make_pair
12 #define pb push_back
13 #define pii pair<int,int>
14 #define mem(a) memset(a,0,sizeof(a))
15 #define prinspace printf("\n")
16 #define fo(a, b) for (int i = (a); i <= (b);i++)
17 const int maxn = 3e5 + 100;
18 const int inf = 0x3f3f3f3f;
19 int a[maxn];
20 int32_t main(){//必须是等腰三角形~
21     int n;
22     scan(n);
23     fo(1, n) scan(a[i]);
24     int m = a[1] % 3, ans = a[1] / 3;
25     for (int i = 2; i <= n;i++){
26         int t = min(a[i] / 2, m);
27         m -= t;
28         ans += t;        
29         a[i] -= 2 * t;
30         ans += a[i] / 3;
31         m += a[i] % 3;//***
32     }
33     prin(ans);
34     //sys;
35     return 0;
36 }

 

 

 

Codeforces 1153C

括号序列。

给一个不完整的括号序列,要求在给定‘?’的区域填上'('或者‘)’使其变成一个合法括号序列

并且这个括号序列需要满足一个条件: 所有严格前缀的括号序列是不合法的

也就是说“()()”不满足题目条件。

因为前缀"()"是合法的

首先,所得到的括号序列中,左右括号的数量一定相等,所以,先在可以填的地方全部填上"("直到”(“数量==n/2

然后全部填完之后,从头到尾扫一遍,如果出现严格前缀中左括号数量==右括号,则输出:(

 1 //codeforces 1153C
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define int long long
 5 #define sys system("pause")
 6 #define scan(n) scanf("%I64d", &(n))
 7 #define scann(n, m) scanf("%I64d%I64d", &(n), &(m))
 8 #define prin(n) printf("%I64d", (n))
 9 #define scannn(a,b,c) scanf("%I64d%I64d%I64d",&(a),&(b),&(c))
10 #define ff first
11 #define ss second
12 #define mp make_pair
13 #define pb push_back
14 #define pii pair<int,int>
15 #define mem(a) memset(a,0,sizeof(a))
16 #define prinspace printf("\n")
17 #define fo(i,a, b) for (int i = (a); i <= (b);i++)
18 #define re(i, a, b) for (int i = (a); i >= (b);i--)
19 const int maxn = 2e5 + 100;
20 const int inf = 0x3f3f3f3f;
21 int32_t main(){
22     int n;
23     scan(n);
24     string s;
25     cin >> s;
26     int l = n / 2, r = n / 2;
27     int a = 0, b = 0;
28     if(s[0]==')'||s[n-1]=='('){
29         printf(":(");
30         return 0;
31     }
32     fo(i,0,n-1)if(s[i]=='(')a++;
33     fo(i,0,n-1)if(s[i]=='?'){
34         if(a<l){s[i] = '(';a++;}
35         else s[i] = ')';
36     }
37     a = 0;
38     fo(i, 0, n - 1){
39         if (s[i] == '(')
40             a++;
41         else
42             b++;
43         if(a==b&&i!=n-1){
44             printf(":(");
45             //sys;
46             return 0;
47         }
48     }
49     if(a!=b)
50         printf(":(");
51     else
52         cout<< s;
53     //sys;
54     return 0;
55 }

 

 

转载于:https://www.cnblogs.com/guaguastandup/p/10639104.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值