国庆 day 1 下午
一道图论好题(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。
思路:当时跑了01分数规划,但是用的bfs找的负环,所以TLE,卡了我5个点。
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 100010
using namespace std;
int n,m,tot;
double w[MAXN],dis[MAXN];
double l=,r=,ans,mid;
int val[MAXN],vis[MAXN],num[MAXN];
int to[MAXN*],net[MAXN*],cap[MAXN*],head[MAXN*];
void add(int u,int v,int w){
to[++tot]=v;net[tot]=head[u];cap[tot]=w;head[u]=tot;
to[++tot]=u;net[tot]=head[v];cap[tot]=w;head[v]=tot;
}
bool spfa(int s){
queue<int>que;
memset(num,,sizeof(num));
memset(vis,,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
que.push(s);
dis[s]=;vis[s]=;num[s]++;
while(!que.empty()){
int now=que.front();
que.pop();
vis[now]=;
for(int i=head[now];i;i=net[i]){
if(dis[to[i]]>dis[now]+w[i]){
dis[to[i]]=dis[now]+w[i];
if(!vis[to[i]]){
vis[to[i]]=;
num[to[i]]++;
que.push(to[i]);
if(num[to[i]]>n) return true;
}
}
}
}
return false;
}
void work(){
for(int i=;i<=tot;i++)
w[i]=(double)cap[i]*mid-val[to[i]];
}
bool check(){
for(int i=;i<=n;i++)
if(spfa(i)) return true;
return false;
}
int main(){
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%d",&val[i]);
for(int i=;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
while(r-l>0.0000001){
mid=(l+r)/;
work();
if(check()){
ans=mid;
l=mid;
}
else r=mid;
}
printf("%.2lf",ans*);
}
然后改成dfs找负环,AC了。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const double eps=1e-;
const int mxn=;
int read(){
int x=,f=;char ch=getchar();
while(ch<'' || ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>='' && ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
struct edge{
int v,nxt,w;
double c;
}e[mxn<<];
int hd[mxn*],mct=;
void add_edge(int u,int v,int w){
e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;e[mct].w=w;return;
}
bool vis[mxn];
double dis[mxn];
bool SPFA(int u){
vis[u]=;
for(int i=hd[u];i;i=e[i].nxt){
int v=e[i].v;
if(dis[v]>dis[u]+e[i].c){
dis[v]=dis[u]+e[i].c;
if(vis[v] || SPFA(v)){
vis[v]=;return ;
}
}
}
vis[u]=;
return ;
}
int n,m;
int f[mxn];
void restore(double r){
for(int i=;i<=mct;i++)
e[i].c=(double)e[i].w*r-f[e[i].v];
return;
}
bool check(){
for(int i=;i<=n;i++)
if(SPFA(i))return ;
return ;
}
int main(){
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
int i,j;
int u,v,w;
n=read();m=read();
for(i=;i<=n;i++)
f[i]=read();
for(i=;i<=m;i++){
u=read();v=read();w=read();
add_edge(u,v,w);
add_edge(v,u,w);
}
double l=,r=,ans;
while(r-l>eps){
double mid=(l+r)/;
restore(mid);
if(check()){
ans=mid;
l=mid;
}else r=mid;
}
printf("%.2f\n",ans*);
return ;
}
后来听老师讲了之后发现这是道结论题:最优解一定是一条边+两个点。
#include <cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
double ans;
int A,B,C,n,m;
int a[];
int main(){
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
for(int i=;i<=m;i++){
scanf("%d%d%d",&A,&B,&C);
ans=max(ans,(a[A]+a[B])/(C+0.0));
}
printf("%.2f\n",ans);
return ;
}
拍照(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<=1000,Wi,Hi<=10。
对于100%的数据1<=n,Wi,Hi<=1000。
思路:考试的时候写了个DP,但是忘了考虑他的后效性,所以挂掉了8个点。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,sumh,sumw;
int ans=0x7f7f7f7f;
int w[],h[];
int f[][],sum[][];
int maxh[][],maxw[][];
int main(){
freopen("photo.in","r",stdin);
freopen("photo.out","w",stdout);
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d%d",&w[i],&h[i]);
sumw+=w[i];
sumh+=h[i];
maxh[i][i]=max(w[i],maxh[i-][i-]);
maxh[i][]=max(h[i],maxh[i-][]);
f[i][]=maxh[i][]*sumw;
f[i][i]=maxh[i][i]*sumh;
sum[i][]=sumw;
sum[i][i]=sumh;
}
for(int i=;i<=n;i++)
for(int j=;j<i;j++){
int bns=;
f[i][j]=f[i-][j];
if(h[i]<=maxh[i-][j]){
f[i][j]+=w[i]*maxh[i-][j];
maxh[i][j]=maxh[i-][j];
}
else if(h[i]>maxh[i-][j]){
f[i][j]+=sum[i-][j]*(h[i]-maxh[i-][j])+w[i]*h[i];
maxh[i][j]=h[i];
}
sum[i][j]=sum[i-][j]+w[i]; if(w[i]<=maxh[i-][j-]) bns+=h[i]*maxh[i-][j-];
else if(w[i]>maxh[i-][j-]) bns+=sum[i-][j-]*(w[i]-maxh[i-][j-])+w[i]*h[i];
if(f[i][j]>f[i-][j-]+bns){
f[i][j]=f[i-][j-]+bns;
maxh[i][j]=max(w[i],maxh[i-][j-]);
sum[i][j]=sum[i-][j-]+h[i];
}
}
for(int i=;i<=n/;i++)
ans=min(f[n][i],ans);
cout<<ans;
}
正解思路:枚举高度,贪心累计宽度
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 1005
using namespace std;
int n,ans=0x7f7f7f7f;
int w[MAXN],h[MAXN],bns[MAXN];
int cmp(int a,int b){
return a>b;
}
int main(){
freopen("photo.in","r",stdin);
freopen("photo.out","w",stdout);
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%d%d",&w[i],&h[i]);
for(int i=;i<=;i++){
int sum=,flag=,cnt=,num=;
for(int j=;j<=n;j++)
if(h[j]<=i&&(w[j]<h[j]||w[j]>i))
sum+=w[j];
else if(w[j]>i&&h[j]>i){
flag=;
break;
}
else if(h[j]>i){
cnt++;
sum+=h[j];
}
else{
bns[++num]=w[j]-h[j];
sum+=w[j];
}
if(flag) continue;
if(cnt>n/) continue;
sort(bns+,bns++num,cmp);
for(int j=;j<=min(n/-cnt,num);j++)
sum-=bns[j];
ans=min(ans,sum*i);
}
cout<<ans;
}
或和异或(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。
思路:倍增。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
bool ok;
int a[][];
int poss,v;
int main(){
freopen("xor.in","r",stdin);
freopen("xor.out","w",stdout);
scanf("%d%d",&n,&m);
int len=pow(,n);
for(int i=;i<=len;i++) scanf("%d",&a[n][i]);
for(int i=n-;i>=;i--){
int l=pow(,i);
if((n-i)%)
for(int j=;j<=l;j++)
a[i][j]=a[i+][(j<<)-]|a[i+][(j<<)];
else
for(int j=;j<=l;j++)
a[i][j]=a[i+][(j<<)-]^a[i+][(j<<)];
}
for(int z=;z<=m;z++){
ok=false;int val,pos;
scanf("%d%d",&pos,&val);
a[n][pos]=val;
if(pos%) poss=pos+;
else{
poss=pos;
pos--;
}
for(int i=n-;i>=;i--)
if((n-i)%){
v=a[i+][pos]|a[i+][poss];
if(v==a[i][(pos>>)+(pos-((pos>>)<<))]){
printf("%d\n",a[][]);
ok=true;
break;
}
a[i][(pos>>)+(pos-((pos>>)<<))]=v;
pos=(pos>>)+(pos-((pos>>)<<));
if(pos%) poss=pos+;
else{
poss=pos;
pos--;
}
}
else{
v=a[i+][pos]^a[i+][poss];
if(v==a[i][(pos>>)+(pos-((pos>>)<<))]){
printf("%d\n",a[][]);
ok=true;
break;
}
a[i][(pos>>)+(pos-((pos>>)<<))]=v;
pos=(pos>>)+(pos-((pos>>)<<));
if(pos%) poss=pos+;
else{
poss=pos;
pos--;
}
}
if(!ok) printf("%d\n",a[][]);
}
}
另一种思路:线段树。
#include<cstdio>
#include<iostream>
#define N 131073
using namespace std;
int n,m;
int sum[N<<],mid[N<<];
void build(int now,int l,int r,int dep){
if(l==r){
scanf("%d",&sum[now]);
return;
}
mid[now]=(l+r)/;
build(now*,l,mid[now],dep+);
build(now*+,mid[now]+,r,dep+);
if((n-dep+)&) sum[now]=(sum[now*]|sum[now*+]);
else sum[now]=(sum[now*]^sum[now*+]);
}
void change(int now,int l,int r,int pos,int w,int dep){
if(l==r){
sum[now]=w;
return;
}
if(pos<=mid[now]) change(now*,l,mid[now],pos,w,dep+);
else change(now*+,mid[now]+,r,pos,w,dep+);
if((n-dep+)&) sum[now]=(sum[now*]|sum[now*+]);
else sum[now]=(sum[now*]^sum[now*+]);
}
int main(){
freopen("xor.in","r",stdin);
freopen("xor.out","w",stdout);
scanf("%d%d",&n,&m);
int s=<<n;
build(,,s,);
while(m--){
int x,y;
scanf("%d%d",&x,&y);
change(,,s,x,y,);
printf("%d\n",sum[]);
}
}
国庆 day 1 下午的更多相关文章
- 国庆 day 7 下午
思路:见博客. #include<iostream> #include<cstdio> #include<cstring> #include<algorith ...
- 国庆 day 2 下午
最大值(max) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有一本书,上面有很多有趣的OI问题.今天LYK看到了这么一道题目: 这里有一个长度为n的 ...
- 国庆 day 6 下午
1.数组异或 (xorarray.pas/c/cpp) (xorarray.in/out) 时间限制:2s/空间限制:256M [题目描述] xor——异或,和 and 与or 一样,是一种重要的逻辑 ...
- 国庆 day 3 下午
a[问题描述] 你是能看到第一题的 friends 呢. ——hja 给你一个只有小括号和中括号和大括号的括号序列,问该序列是否合法.[输入格式] 一行一个括号序列.[输出格式] 如果合法,输出 OK ...
- 2018国庆YALI集训游记
想了想,像之前那样简略地叙述题意和做法,根本没讲清楚,没有任何意义,还不如写写自己的感受. 感觉YALI真的是一所挺不错的学校吧.总是能有一机房的julao轮番吊打你,总是能有集训队的奆佬来给你出dl ...
- 2016.10.4初中部下午NOIP普及组比赛总结
2016.10.4初中部下午NOIP普及组比赛总结 这次的题有些水,只是第四题有点坑. 题目: 比赛:AC+0+AC+50=250 改题:AC+AC+AC+50=350 一.Bill 满地都是水 题目 ...
- 票房和口碑称霸国庆档,用 Python 爬取猫眼评论区看看电影《我和我的家乡》到底有多牛
今年的国庆档电影市场的表现还是比较强势的,两名主力<我和我的家乡>和<姜子牙>起到了很好的带头作用. <姜子牙>首日破 2 亿,一举刷新由<哪吒之魔童降世&g ...
- 搞了我一下午竟然是web.config少写了一个点
Safari手机版居然有个这么愚蠢的bug,浪费了我整个下午,使尽浑身解数,国内国外网站搜索解决方案,每一行代码读了又想想了又读如此不知道多少遍,想破脑袋也想不通到底哪里出了问题,结果竟然是web.c ...
- System.DateUtils 3. IsPM、IsAM 判断是否为上、下午
编译版本:Delphi XE7 function IsPM(const AValue: TDateTime): Boolean; inline;function IsAM(const AValue: ...
随机推荐
- [读书笔记] R语言实战 (四) 基本数据管理
1. 创建新的变量 mydata<-data.frame(x1=c(2,2,6,4),x2=c(3,4,2,8)) #方法一 mydata$sumx<-mydata$x1+mydata$x ...
- springmvcjson中文乱码处理
在sping.xml中增加配置信息 <bean class="org.springframework.web.servlet.mvc.method.annotation.Request ...
- Ubuntu 15.10 安装Qt5.5.1
本系列文章由 @YhL_Leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/50300447 本人使用的ubuntu系 ...
- PatentTips - Safe general purpose virtual machine computing system
BACKGROUND OF THE INVENTION The present invention relates to virtual machine implementations, and in ...
- javascript-知识点集合
第三课.JavaScript的语法与关键字 1.JavaScript的语法 字符串.数字.布尔.数组.对象.Null.Undefined 1.js的变量区分大小写 username userName ...
- [CSS3] Responsive Table -- no more table
When the screen size is small, we can use "no more table" solution. So instead of render t ...
- ACM-ICPC Dhaka Regional 2012 题解
B: Uva: 12582 - Wedding of Sultan 给定一个字符串(仅由大写字母构成)一个字母表示一个地点,经过这个点或离开这个点都输出这个地点的字母) 问: 每一个地点经过的次数(维 ...
- hibernate配置数据库连接池三种用法
三种连接都是以连接MySQl为例. <!-- JDBC驱动程序 --> <property name="connection.driver_class">o ...
- oracle日常维护语句
1.如何查看数据库的状态 unix下 ps -ef | grep ora windows下 看服务是否起来 是否可以连上数据库 SQL> select status, instance_r ...
- POJ 1951 模拟
思路: 坑爹模拟毁我一生 给两组数据: 输入: YOURE TRAVELING THROUGH ANOTHER DIMENSION A DIMENSION NOT OF SIGHT. 输出: YR T ...