码迷,mamicode.com
首页 > 其他好文 > 详细

清北学堂D1下

时间:2017-10-20 20:20:29      阅读:314      评论:0      收藏:0      [点我收藏+]

标签:rod   范围   通过   acs   pil   dep   dac   pat   pcb   

T1

一道图论好题(graph)

Time Limit:1000ms   Memory Limit:128MB

题目描述

LYK有一张无向图G={V,E},这张无向图有n个点m条边组成。并且这是一张带权图,不仅有边权还有点权。

LYK给出了一个子图的定义,一张图G’={V’,E’}被称作G的子图,当且仅当

·G的点集V包含于G的点集V。

·对于E中的任意两个点a,b∈V’,当(a,b)∈E时,(a,b)一定也属于E,并且连接这两个点的边的边权是一样的。

LYK给一个子图定义了它的价值,它的价值为:点权之和与边权之和的比。 看

LYK想找到一个价值最大的非空子图,所以它来找你帮忙啦。

 

输入格式(graph.in)

第一行两个数n,m表示一张n个点m条边的图。

第二行n个数ai表示点权。

接下来m行每行三个数u,v,z,表示有一条连接u,v的边权为z的无向边。数据保证任意两个点之间最多一条边相连,并且不存在自环。

输出格式(graph.out)

你需要输出这个价值最大的非空子图的价值,由于它是一个浮点数,你只需要保留小数点后两位有效数字。 

 

输入样例

3 3

2 3 4

1 2 3

1 3 4

2 3 5

输出样例

1.67

样例解释

 

选择1,2两个点,则价值为5/3=1.67。

对于20%的数据n=2

对于50%的数据n<=5

对于100%的数据1<=n,m<=1000001<=ai,z<=1000。

思路:其实是贪心,(我开始也没想出来,看到超短的std时才惊叹)贪心的结论是最优的情况一定只存在于两个点和一条边的情况。

证明:如果多个点要被选,那么可以转化为在一条链的时候一定有比两个点更优的情况存在,考虑最简单的三个点的情况;

技术分享

好了,如果a,b单独连,则整个的价值为f1=(a+b)/w1,同理若b,c单独相连,价值为放f2=(b+c)/w2;abc一起连,为f=(a+b+c)/(w1+w2)

考虑  f>f1&&f>f2推出矛盾,n>3考虑归纳;                  
或者这样说,如果加入一个点比前面的n-1个点优,那么这个点一定可构造出更优解。   

(好像我说的不是很清楚。。水平有限)

 

技术分享
 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cmath>
 5 #define N 100010
 6 #define Run(i,l,r) for(int i=l;i<=r;i++)
 7 #define Don(i,l,r) for(int i=l;i>=r;i--)
 8 using namespace std;
 9 int n,m;
10 int G[N];
11 int main()
12 {    freopen("graph.in","r",stdin);
13     freopen("graph.out","w",stdout);
14     cin>>n>>m;    
15     Run(i,1,n){
16         scanf("%d",&G[i]);
17     }
18     double ans=0;
19     int u,v,E;
20     Run(i,1,m){
21         scanf("%d%d%d",&u,&v,&E);
22         ans=max(ans,1.0*(G[u]+G[v])/E);
23     }
24     printf("%.2lf\n",ans);
25     return 0;
26 }
View Code

 

 

 

拍照(photo)

Time Limit:1000ms   Memory Limit:128MB

 

题目描述

假设这是一个二次元。

LYK召集了n个小伙伴一起来拍照。他们分别有自己的身高Hi和宽度Wi。

为了放下这个照片并且每个小伙伴都完整的露出来,必须需要一个宽度为ΣWi,长度为max{Hi}的相框。(因为不能叠罗汉)。

LYK为了节省相框的空间,它有了绝妙的idea,让部分人躺着!一个人躺着相当于是身高变成了Wi,宽度变成了Hi。但是很多人躺着不好看,于是LYK规定最多只有n/2个人躺着。(也就是说当n=3时最多只有1个人躺着,当n=4时最多只有2个人躺着)

LYK现在想问你,当其中部分人躺着后,相框的面积最少是多少。

 

输入格式(photo.in)

第一行一个数n。

    接下来n行,每行两个数分别是Wi,Hi

 

输出格式(photo.out)

你需要输出这个相框的面积最少是多少。

 

输入样例

3

3 1

2 2

4 3

 

输出样例

27

 

样例解释

如果没人躺过来,需要27的面积。

我们只要让第1个人躺过来,就只需要21的面积!

 

对于30%的数据n<=10。

对于60%的数据n<=1000Wi,Hi<=10

对于100%的数据1<=n,Wi,Hi<=1000

思路

如果有两个变化的量不好决策,我们控制高度,就可以得到以下决策(H为控制的相框高度,hi,wi为当前的高度宽度):

若  1) hi<=H&&wi>H 一定不能让他躺下;

    3) hi>H&&wi<=H 一定要躺下;

    2) hi<=H&&wi<=H 可躺可不躺,为了让宽度最小(因为此时H一定),我们在保证人数的前提下,让(hi-wi)小的躺下;

    4) hi>H&&wi>H 就是不合法的情况,可以通过H的枚举范围pass掉;

再说下H的范围,下界min(min(wi,hi)) 下界min(max(wi,hi))(自己想想,其实只是一种简化);

或和异或(xor)

 

技术分享
 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define inf 0x3f3f3f3f
 6 #define N 1010
 7 #define Run(i,l,r) for(int i=l;i<=r;i++)
 8 #define Don(i,l,r) for(int i=l;i>=r;i--)
 9 using namespace std;
10 int n,lim,w[N],h[N],up=0,down=0;
11 struct node{
12     int k,x;
13     bool operator < (const node aa) const {return aa.x>x;}
14 }a[N];
15 int main()
16 {    freopen("photo.in","r",stdin);
17     //freopen("photo.out","w",stdout);
18     cin>>n;
19     lim=n/2;
20     int tot=0;
21     Run(i,1,n){
22         scanf("%d%d",&w[i],&h[i]);
23         up=max(up,max(w[i],h[i]));
24         down=max(down,min(w[i],h[i]));
25         if (h[i]<w[i]) a[++tot]=(node){i,(h[i]-w[i])};    
26     }
27     sort(a+1,a+tot+1);
28     int ans=inf;
29     Don(i,up,down){
30         int temp=0,cnt=0;
31         Run(j,1,n){
32             if (h[j]>i) {cnt++;
33                           temp+=h[j];
34                         }
35             else if (h[j]>=w[j]||w[j]>i) temp+=w[j];
36         }
37         if (cnt>lim) break;
38         Run(j,1,tot){
39             if (h[a[j].k]<=i&&w[a[j].k]<=i) {
40             if (cnt<lim){
41             temp+=h[a[j].k];
42             cnt++;
43             }
44             else temp+=w[a[j].k];
45             }
46         }
47     if (ans>temp*i) {
48     //cout<<temp<<" "<<i<<endl; 
49     ans=temp*i;}
50     }
51     cout<<ans<<endl;
52     return 0;
53 }
View Code

 

 

 

Time Limit:2000ms   Memory Limit:128MB

 

题目描述

LYK最近在研究位运算,它研究的主要有两个:or和xor。(C语言中对于|和^)

为了更好的了解这两个运算符,LYK找来了一个2^n长度的数组。它第一次先对所有相邻两个数执行or操作,得到一个2^(n-1)长度的数组。也就是说,如果一开始时a[1],a[2],…,a[2^n],执行完第一次操作后,会得到a[1] or a[2],a[3] or a[4] ,…, a[(2^n)-1] or a[2^n]

第二次操作,LYK会将所有相邻两个数执行xor操作,得到一个2^(n-2)长度的数组,假如第一次操作后的数组是b[1],b[2],…,b[2^(n-1)],那么执行完这次操作后会变成b[1] xor b[2], b[3] xor b[4] ,…, b[(2^(n-1))-1] xor b[2^(n-1)]

第三次操作,LYK仍然将执行or操作,第四次LYK执行xor操作。如此交替进行。

最终这2^n个数一定会变成1个数。LYK想知道最终这个数是多少。

为了让这个游戏更好玩,LYK还会执行Q次修改操作。每次修改原先的2^n长度的数组中的某一个数,对于每次修改操作,你需要输出n次操作后(最后一定只剩下唯一一个数)剩下的那个数是多少。

 

输入格式(xor.in)

第一行两个数n,Q。

接下来一行2^n个数ai表示一开始的数组。

接下来Q行,每行两个数xi,yi,表示LYK这次的修改操作是将a{xi}改成yi。

 

输出格式(xor.out)

Q行,表示每次修改操作后执行n次操作后剩下的那个数的值。

 

输入样例

2 4

1 6 3 5

1 4

3 4

1 2

1 2

 

输出样例

1

3

3

3

 

样例解释

第一次修改,{4,6,3,5}->{6,7}->{1}

第二次修改,{4,6,4,5}->{6,5}->{3}

第三次修改,{2,6,4,5}->{6,5}->{3}

第四次修改,{2,6,4,5}->{6,5}->{3}

对于30%的数据n<=17Q=1

对于另外20%的数据n<=10,Q<=1000。

对于再另外30%的数据n<=12,Q<=100000。

对于100%的数据1<=n<=171<=Q<=10^51<=xi<=2^n,0<=yi<2^300<=ai<2^30。

思路:

由于是2^n很容易想到线段树,有点小改动就是要记录深度,用深度的奇偶来规定运算(也有其他做法,但我觉得这个自然点);

 

技术分享
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #define N 140000
 6 #define ll long long
 7 #define Run(i,l,r) for(int i=l;i<=r;i++)
 8 #define Don(i,l,r) for(int i=l;i>=r;i--)
 9 using namespace std;
10 struct node{
11     int left,right,x;
12 }tree[4*N];
13 int n,q;
14 void Build(int id,int l,int r,int dep)
15 {    tree[id].left=l; tree[id].right=r; 
16     if (l==r) scanf("%d",&tree[id].x);
17     else {
18         int mid=(l+r)/2;
19         Build(2*id,l,mid,dep-1);
20         Build(2*id+1,mid+1,r,dep-1);
21         if (dep&1) tree[id].x=tree[2*id].x|tree[2*id+1].x;
22         else tree[id].x=tree[2*id].x^tree[2*id+1].x;
23     }
24 }
25 void update(int id,int k,int x,int dep)
26 {    if (tree[id].left==tree[id].right) tree[id].x=x;
27     else {int mid=(tree[id].left+tree[id].right)/2;
28          if (k<=mid)  update(2*id,k,x,dep-1);
29           else update(2*id+1,k,x,dep-1);
30          if (dep&1) tree[id].x=tree[2*id].x|tree[2*id+1].x;
31            else tree[id].x=tree[2*id].x^tree[2*id+1].x;
32          }
33 }
34 int main()
35 {    freopen("xor.in","r",stdin);
36     freopen("xor.out","w",stdout);
37     cin>>n>>q;
38     Build(1,1,1<<n,n);
39     int x,k;
40     Run(i,1,q){
41         cin>>k>>x;
42         update(1,k,x,n);
43         printf("%d\n",tree[1].x);
44     }
45     return 0;
46 }//by tkys_Austin; 
View Code

 

 

 

 

清北学堂D1下

标签:rod   范围   通过   acs   pil   dep   dac   pat   pcb   

原文地址:http://www.cnblogs.com/AUSTIN-tkys/p/7701085.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!