2017-10-01-afternoon

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<=100000,1<=ai,z<=1000。

 大忽悠题。。

 1 /*
 2 设点1,2,之间边权w12,点2,3,之间边权w23
 3 假设 t1=(v1+v2)/w12>(v2+v3)/w23,即
 4       v1*w23+v2*w23>v2*w12+v3*w12
 5 那么 如果在1,2这个图里再加上3这个点
 6      t2==(v1+v2+v3)/(w12+w23)
 7 如果 t1>t2   移项一下就是
 8      v1*w12+v1*w23+v2*w12+v2*w23>v1*w12+v2*w12+v3*w12
 9 又因为v1*w23+v2*w23>v2*w12+v3*w12
10 所以t1>t2显然,所以就是找两个点的图
11 */
12 #include <cstdio>
13 
14 #define max(a,b) (a>b?a:b)
15 
16 inline void read(int &x)
17 {
18     x=0; register char ch=getchar();
19     for(; ch>'9'||ch<'0'; ) ch=getchar();
20     for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
21 }
22 const int N(100005);
23 int n,m,val[N];
24 double ans;
25 
26 int Presist()
27 {
28 //    freopen("graph.in","r",stdin);
29 //    freopen("graph.out","w",stdout);
30     read(n),read(m);
31     for(int i=1; i<=n; ++i) read(val[i]);
32     for(int u,v,w; m--; )
33     {
34         read(u),read(v),read(w);
35         ans=max(ans,1.0*(val[u]+val[v])/w);
36     }
37     printf("%.2lf",ans);
38     return 0;
39 }
40 
41 int Aptal=Presist();
42 int main(int argc,char**argv){;} 
AC

T2 拍照(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

输出样例

21

样例解释

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

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

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

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

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

 1 /*
 2 气人诶。。。
 3 一开始二分高度,,然后WA3个点。
 4 然后高度从大到小枚举,就A了。 
 5 
 6 对于每个人,判断在当前高度下是否需要躺下,且躺下是否合法
 7 当所有人的高度都符合要求时,如果还有让人躺下的次数
 8 判断每个人在躺下后,是否比站着更优 (sort一下方便) 
 9 */
10 #include <algorithm>
11 #include <cstdio>
12 
13 #define max(a,b) (a>b?a:b)
14 
15 inline void read(int &x)
16 {
17     x=0; register char ch=getchar();
18     for(; ch>'9'||ch<'0'; ) ch=getchar();
19     for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
20 }
21 const int N(1e3+5);
22 int n,W,H;
23 struct People {
24     int w,h;
25     bool operator < (const People&x)const
26     {
27         return w-h>x.w-x.h;
28 //        if(h!=x.h) return h>x.h;
29 //        return w<x.w;
30     }
31 }peo[N];
32 
33 int l,r,mid,ans=0x7fffffff,tmp;
34 inline bool check(int nowh)
35 {
36     int cnt=n>>1,ret=0,sw=W;
37     for(int i=1; i<=n; ++i)
38      if(peo[i].h>nowh)
39      {
40          sw-=peo[i].w;
41          sw+=peo[i].h;
42          if(peo[i].w>nowh) return 0;
43         if(--cnt<0) return 0;
44      }
45     for(int i=1; cnt&&i<=n; ++i)
46       if(peo[i].h<=nowh&&peo[i].h<peo[i].w&&peo[i].w<=nowh)
47         sw-=peo[i].w,sw+=peo[i].h,cnt--;
48     if(tmp*nowh<ans) tmp=sw; return tmp*nowh<ans;
49 }
50 
51 int Presist()
52 {
53     freopen("photo.in","r",stdin);
54     freopen("photo.out","w",stdout);
55     read(n);
56     for(int i=1; i<=n; ++i)
57     {
58         read(peo[i].w),read(peo[i].h);
59         W+=peo[i].w;H=max(H,peo[i].h);
60     }
61     std::sort(peo+1,peo+n+1);
62     for(; check(H); H--) ans=H*tmp;
63     /*for(r=H; l<=r; )
64     {
65         mid=l+r>>1;
66         if(check(mid))
67         {
68             ans=mid*tmp;
69             r=mid-1;
70         }
71         else l=mid+1;
72     }*/
73     printf("%d
",ans);
74     return 0;
75 }
76 
77 int Aptal=Presist();
78 int main(int argc,char**argv){;}
枚举+贪心AC

T3 或和异或(xor)

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<=17,Q=1。

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

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

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

 1 #include <cstdio>
 2 
 3 inline void read(int &x)
 4 {
 5     x=0; register char ch=getchar();
 6     for(; ch>'9'||ch<'0'; ) ch=getchar();
 7     for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
 8 }
 9 const int N(5e6+5);
10 int n,q,a[N],x[N];
11 
12 inline int work()
13 {
14     int cnt1=0,cnt2=1<<n;
15     for(int i=1; i<=1<<n; ++i) x[i]=a[i];
16     for(; 1; )
17     {
18         cnt1=0;
19         for(int i=1; i<=cnt2; i+=2)
20             x[++cnt1]=x[i]|x[i+1];
21         if(cnt1==1) return x[1];
22         cnt2=0;
23         for(int i=1; i<=cnt1; i+=2)
24             x[++cnt2]=x[i]^x[i+1];
25         if(cnt2==1) return x[1];
26     }
27     
28 }
29 
30 int Presist()
31 {
32 //    freopen("xor.in","r",stdin);
33 //    freopen("xor.out","w",stdout);
34     read(n),read(q);
35     for(int i=1; i<=1<<n; ++i) read(a[i]);
36     for(int pos,num; q--; )
37     {
38         read(pos),read(num);
39         a[pos]=num;
40         printf("%d
",work());
41     }
42     return 0;
43 }
44 
45 int Aptal=Presist();
46 int main(int argc,char**argv){;}
搞笑的50分暴力
 1 /*
 2 数的个数依次减少,每次有类似操作——>>线段树维护
 3 对于一个区间,标记他的父亲是需要 | 得到还是 ^ 得到 
 4 */
 5 #include <cstdio>
 6 
 7 inline void read(int &x)
 8 {
 9     x=0; register char ch=getchar();
10     for(; ch>'9'||ch<'0'; ) ch=getchar();
11     for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
12 }
13 const int N(1<<18);
14 
15 struct Tree {
16     bool flag;
17     int l,r,mid,val;
18 }tr[N<<2];
19 
20 #define lc (now<<1)
21 #define rc (now<<1|1)
22 #define mid (tr[now].l+tr[now].r>>1)
23 
24 void Tree_update(int now)
25 {
26     tr[now].flag=!tr[lc].flag;
27     if(!tr[lc].flag)
28          tr[now].val=tr[lc].val|tr[rc].val;
29     else tr[now].val=tr[lc].val^tr[rc].val;
30 }
31 void Tree_build(int now,int l,int r)
32 {
33     tr[now].l=l; tr[now].r=r;
34     if(l==r) { read(tr[now].val),tr[now].flag=0;return ; }
35     Tree_build(lc,l,mid);    Tree_build(rc,mid+1,r);
36     Tree_update(now);
37 }
38 void Tree_change(int now,int to,int x)
39 {
40     if(tr[now].l==tr[now].r) {tr[now].val=x; return ;}
41     if(to<=mid) Tree_change(lc,to,x);
42     else Tree_change(rc,to,x);
43     Tree_update(now);
44 }
45 
46 int Presist()
47 {
48     freopen("xor.in","r",stdin);
49     freopen("xor.out","w",stdout);
50     int n,q;    read(n),read(q);
51     Tree_build(1,1,1<<n);
52     for(int pos,num; q--; )
53     {
54         read(pos),read(num);
55         Tree_change(1,pos,num);
56         printf("%d
",tr[1].val);
57     }
58     return 0;
59 }
60 
61 int Aptal=Presist();
62 int main(int argc,char**argv){;}
线段树 AC
 1 #include <cmath>
 2 #include <cstdio>
 3 #include <iostream>
 4 #include <cstdlib>
 5 #include <algorithm>
 6 #include <string>
 7 #include <cstring>
 8 using namespace std;
 9 long long st[131073][18];
10 int next[18][131073],i,j,n,m,now,k,A,B;
11 int main()
12 {
13     freopen("xor.in","r",stdin);
14     freopen("xor.out","w",stdout);
15     scanf("%d%d",&n,&m);
16     for (i=1; i<=(1<<n); i++) cin>>st[i][0];
17     for (i=1; i<=n; i++)
18     {
19         for (j=1; j<=(1<<n); j+=(1<<i))
20         {
21             if (i % 2==1) st[j][i]=st[j][i-1]|st[j+(1<<(i-1))][i-1]; else
22               st[j][i]=st[j][i-1]^st[j+(1<<(i-1))][i-1];
23         }
24     }
25     for (i=1; i<=n; i++)
26       for (j=1; j<=(1<<n); j+=(1<<i))
27       {
28           for (k=j; k<=j+(1<<i)-1; k++)
29             next[i][k]=j;
30       }
31     for (i=1; i<=m; i++)
32     {
33         scanf("%d%d",&A,&B);
34         st[A][0]=B;
35         for (j=1; j<=n; j++)
36         {
37             now=next[j][A];
38             if (j % 2==1) st[now][j]=st[now][j-1]|st[now+(1<<(j-1))][j-1]; else
39                 st[now][j]=(st[now][j-1]^st[now+(1<<(j-1))][j-1]);
40         }
41         cout<<st[1][n]<<endl;
42     }
43     return 0;
44 }
std的set表
——每当你想要放弃的时候,就想想是为了什么才一路坚持到现在。
原文地址:https://www.cnblogs.com/Shy-key/p/7647661.html