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){;}
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){;}
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){;}
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){;}
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 }