20160522~20160528

20160523

bzoj2561 http://www.lydsy.com/JudgeOnline/problem.php?id=2561

题意:给定一个连通无向图,假设现在加入一条边权为L的边(u,v),求需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树上。N≤20000,M≤200000

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #define maxn 30000
 6 #define inc(i,j,k) for(int i=j;i<=k;i++)
 7 #define INF 0x3fffffff
 8 using namespace std;
 9
10 struct e{int t,c,n;}; e es[maxn*40]; int g[maxn],ess;
11 inline void pe(int f,int t,int c){
12     es[++ess]=(e){t,c,g[f]}; g[f]=ess; es[++ess]=(e){f,0,g[t]}; g[t]=ess;
13 }
14 inline void init(){
15     ess=-1; memset(g,-1,sizeof(g));
16 }
17 queue <int> q; int h[maxn];
18 bool bfs(int s,int t){
19     memset(h,-1,sizeof(h)); while(!q.empty())q.pop(); h[s]=0; q.push(s);
20     while(! q.empty()){
21         int x=q.front(); q.pop();
22         for(int i=g[x];i!=-1;i=es[i].n)if(es[i].c&&h[es[i].t]==-1)h[es[i].t]=h[x]+1,q.push(es[i].t);
23     }
24     return h[t]!=-1;
25 }
26 int dfs(int x,int t,int f){
27     if(x==t)return f; int u=0;
28     for(int i=g[x];i!=-1;i=es[i].n)if(es[i].c&&h[es[i].t]==h[x]+1){
29         int w=dfs(es[i].t,t,min(f,es[i].c)); f-=w; u+=w; es[i].c-=w; es[i^1].c+=w; if(f==0)return u;
30     }
31     if(u==0)h[x]=-1; return u;
32 }
33 int dinic(int s,int t){
34     int f=0; while(bfs(s,t))f+=dfs(s,t,INF); return f;
35 }
36 int n,m,u[maxn*10],v[maxn*10],w[maxn*10],U,V,L;
37 int main(){
38     scanf("%d%d",&n,&m); inc(i,1,m)scanf("%d%d%d",&u[i],&v[i],&w[i]); scanf("%d%d%d",&U,&V,&L); int ans=0;
39     init(); inc(i,1,m)if(w[i]<L)pe(u[i],v[i],1),pe(v[i],u[i],1); ans+=dinic(U,V);
40     init(); inc(i,1,m)if(w[i]>L)pe(u[i],v[i],1),pe(v[i],u[i],1); ans+=dinic(U,V);
41     printf("%d",ans); return 0;
42 }

题解:最小割。如果一个边出现在最小生成树上,那么权值比它小的边一定不能使图联通。因为要求删掉最少,所以当加入这条边后整个图刚好联通。因此可以将这条边的一个端点作为源,另一端点作为汇,插入所以权值比L小的边,每条边流量为1,跑最小割,求出来的答案就是使源、汇不联通最少删掉边。最大生成树同理,插入的是权值比L大的。最后答案是两次跑最小割的结果相加。

吐槽:注意边要开到4倍,而且图中边是无向边,在网络流插边时要插两个方向。这道题也告诉我们实际上数据范围上万的可能也是用网络流。dinic/ISAP的玄学复杂度QAQ

2、bzoj1024 http://www.lydsy.com/JudgeOnline/problem.php?id=1024

题意:一个矩形蛋糕边长分别为X和Y,须切成N块面积相等的蛋糕。每一切只能平行于一块蛋糕的任意一边,并且必须把这块蛋糕切成两块。因此必须切 N-1 次。求 N块蛋糕的长边与短边的比值的最大值的最小值。X,Y≤10000,N≤10

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define INF 0x3fffffff
 5 #define inc(i,j,k) for(double i=j;i<=k;i++)
 6 using namespace std;
 7
 8 double dfs(double x,double y,double cnt){
 9     if(cnt==1)return max(x,y)/min(x,y); double ans=INF;
10     inc(i,1,cnt-1){
11         ans=min(ans,max(dfs(x/cnt*i,y,i),dfs(x/cnt*(cnt-i),y,cnt-i)));
12         ans=min(ans,max(dfs(x,y/cnt*i,i),dfs(x,y/cnt*(cnt-i),cnt-i)));
13     }
14     return ans;
15 }
16 int x,y,n;
17 int main(){
18     scanf("%d%d%d",&x,&y,&n); printf("%.6lf",dfs((double)x,(double)y,(double)n)); return 0;
19 }

题解:爆搜,dfs(x,y,cnt)表示要把长为x宽为y的蛋糕切成cnt块,因为只能切在x/cnt或y/cnt的倍数的位置上,所以每次枚举切哪个位置就行了。

20160524

3、bzoj1034 http://www.lydsy.com/JudgeOnline/problem.php?id=1034

题意:n场比赛,知道自己所有选手的能力值和对方所有选手的能力值,能力值大的一定赢。比赛赢一场得2分,平局得1分,输了不得分。对方随机决定选手顺序,你想知道自己最多能得多少分和最少能得多少分。N≤100000

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define maxn 200000
 6 using namespace std;
 7
 8 int a[maxn],b[maxn],n,ans,la,ra,lb,rb;
 9 int main(){
10     scanf("%d",&n); inc(i,1,n)scanf("%d",&a[i]); inc(i,1,n)scanf("%d",&b[i]); sort(a+1,a+1+n); sort(b+1,b+1+n);
11     ans=0; la=1; ra=n; lb=1; rb=n;
12     inc(i,1,n){
13         if(a[ra]>b[rb])ra--,rb--,ans+=2;else if(a[la]>b[lb])la++,lb++,ans+=2;else ans+=(a[la]==b[rb]),la++,rb--;
14     }
15     printf("%d ",ans); swap(a,b);
16     ans=0; la=1; ra=n; lb=1; rb=n;
17     inc(i,1,n){
18         if(a[ra]>b[rb])ra--,rb--,ans+=2;else if(a[la]>b[lb])la++,lb++,ans+=2;else ans+=(a[la]==b[rb]),la++,rb--;
19     }
20     printf("%d",2*n-ans); return 0;
21 }

题解:贪心。设一个高分方和低分方,将两方选手按能力排好序。如果高分方目前最强能赢低分方目前最强,就让他们比赛;

如果高分方目前最弱能赢低分方目前最弱,也让他们比赛;否则用高分方最弱的和低分方最强的打。开始先让自己方为高分方,求最大值,再让对方做高分方,本方最小值就是2*n-对方得分。

4、bzoj1497 http://www.lydsy.com/JudgeOnline/problem.php?id=1497

题意:N个地方,在i处建立通讯中转站需要的成本为Pi。M个用户,第i个用户会使用中转站Ai和中转站Bi进行通讯,公司可以获益Ci。求净获利最大值。N≤5000,M≤50000

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #define maxn 60000
 6 #define inc(i,j,k) for(int i=j;i<=k;i++)
 7 #define INF 0x3fffffff
 8 using namespace std;
 9
10 struct e{int t,c,n;}; e es[maxn*20]; int g[maxn],ess;
11 inline void pe(int f,int t,int c){
12     es[++ess]=(e){t,c,g[f]}; g[f]=ess; es[++ess]=(e){f,0,g[t]}; g[t]=ess;
13 }
14 inline void init(){
15     ess=-1; memset(g,-1,sizeof(g));
16 }
17 queue <int> q; int h[maxn];
18 bool bfs(int s,int t){
19     memset(h,-1,sizeof(h)); while(!q.empty())q.pop(); h[s]=0; q.push(s);
20     while(! q.empty()){
21         int x=q.front(); q.pop();
22         for(int i=g[x];i!=-1;i=es[i].n)if(es[i].c&&h[es[i].t]==-1)h[es[i].t]=h[x]+1,q.push(es[i].t);
23     }
24     return h[t]!=-1;
25 }
26 int dfs(int x,int t,int f){
27     if(x==t)return f; int u=0;
28     for(int i=g[x];i!=-1;i=es[i].n)if(es[i].c&&h[es[i].t]==h[x]+1){
29         int w=dfs(es[i].t,t,min(f,es[i].c)); f-=w; u+=w; es[i].c-=w; es[i^1].c+=w; if(f==0)return u;
30     }
31     if(u==0)h[x]=-1; return u;
32 }
33 int dinic(int s,int t){
34     int f=0; while(bfs(s,t))f+=dfs(s,t,INF); return f;
35 }
36 int n,m,s,t,tot;
37 int main(){
38     scanf("%d%d",&n,&m); s=0; t=n+m+1; init();
39     inc(i,1,n){int a; scanf("%d",&a); pe(s,i,a);}
40     inc(i,1,m){int a,b,c; scanf("%d%d%d",&a,&b,&c); pe(a,n+i,INF); pe(b,n+i,INF); pe(n+i,t,c); tot+=c;}
41     printf("%d",tot-dinic(s,t)); return 0;
42 }

题解:最小割。源点向所有地方连边,流量为建站成本,第Ai个地方和第Bi个地方分别向第i个用户连边,流量无穷,所有用户向汇点连边,流量为获益。这样割源点与地方的连边表示付出成本,割用户与汇点的连边表示放弃利益。最后答案是所有获益和-最小割。

20160525

5、bzoj1878 http://www.lydsy.com/JudgeOnline/problem.php?id=1878

题意:N个数,M个询问求区间[L,R]中包含了多少种不同的数。N≤50000,M≤200000

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define maxn 50100
 6 #define lb(x) x&-x;
 7 using namespace std;
 8
 9 int a[maxn],last[maxn*20],next[maxn],sm[maxn],n,m;
10 struct ask{int l,r,ans,id;}; ask asks[maxn*6];
11 bool cmp1(ask a,ask b){return a.l<b.l;}
12 bool cmp2(ask a,ask b){return a.id<b.id;}
13 inline void update(int x,int v){while(x<=n){sm[x]+=v,x+=lb(x);}}
14 inline int query(int x){int q=0; while(x>0){q+=sm[x],x-=lb(x);} return q;}
15 int main(){
16     scanf("%d",&n); inc(i,1,n)scanf("%d",&a[i]);
17     scanf("%d",&m); inc(i,1,m)scanf("%d%d",&asks[i].l,&asks[i].r),asks[i].id=i;
18     memset(last,0,sizeof(last)); inc(i,1,n){if(last[a[i]])next[last[a[i]]]=i;else update(i,1); last[a[i]]=i;}
19     sort(asks+1,asks+1+m,cmp1); int l=1;
20     inc(i,1,m){
21         while(l<asks[i].l){if(next[l])update(next[l],1); l++;}
22         asks[i].ans=query(asks[i].r)-query(asks[i].l-1);
23     }
24     sort(asks+1,asks+1+m,cmp2); inc(i,1,m)printf("%d\n",asks[i].ans);
25     return 0;
26 }

题解:莫队好像可以做~但正解是树状数组。先将询问按左端点排序,并求出每个数的下一个与它相等的数的位置,同时将每个数第一次出现的位置在树状数组中置为1,此时query(x)求出来的就是1到x里有多少个不同的数。枚举排序后的询问,将当前左端点向右移动,每右移一位就将原位置的数的下一个与它相同的数的位置在树状数组中置为1,保证如果这个数在[l,r]中出现不会漏算。当左端点移动到询问的左端点位置时,就输出query(r)-query(l-1),表示l到r里有多少个不同的数。

20160527

6、bzoj1047 http://www.lydsy.com/JudgeOnline/problem.php?id=1047

题意:有一个a*b的整数组成的矩阵,求一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。a,b≤1000,n≤100

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define maxn 1500
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 #define INF 2147483647
 7 using namespace std;
 8
 9 int maxh[maxn][maxn],minh[maxn][maxn],maxl[maxn][maxn],minl[maxn][maxn];
10 int v[maxn][maxn],q1[maxn],q2[maxn],a,b,n,l,r,ans;
11 int main(){
12     scanf("%d%d%d",&a,&b,&n); inc(i,1,a)inc(j,1,b)scanf("%d",&v[i][j]);
13     inc(i,1,a){
14         l=1; r=0;
15         inc(j,1,n){while(r>=l&&v[i][j]>q1[r])r--; q1[++r]=v[i][j]; q2[r]=j;} maxh[i][1]=q1[l];
16         inc(j,n+1,b){
17             if(j-n>=q2[l])l++; while(r>=l&&v[i][j]>q1[r])r--;
18             q1[++r]=v[i][j]; q2[r]=j; maxh[i][j-n+1]=q1[l];
19         }
20     }
21     inc(i,1,a){
22         l=1; r=0;
23         inc(j,1,n){while(r>=l&&v[i][j]<q1[r])r--; q1[++r]=v[i][j]; q2[r]=j;} minh[i][1]=q1[l];
24         inc(j,n+1,b){
25             if(j-n>=q2[l])l++; while(r>=l&&v[i][j]<q1[r])r--;
26             q1[++r]=v[i][j]; q2[r]=j; minh[i][j-n+1]=q1[l];
27         }
28     }
29     inc(j,1,b){
30         l=1; r=0;
31         inc(i,1,n){while(r>=l&&maxh[i][j]>q1[r])r--; q1[++r]=maxh[i][j]; q2[r]=i;} maxl[1][j]=q1[l];
32         inc(i,n+1,a){
33             if(i-n>=q2[l])l++; while(r>=l&&maxh[i][j]>q1[r])r--;
34             q1[++r]=maxh[i][j]; q2[r]=i; maxl[i-n+1][j]=q1[l];
35         }
36     }
37     inc(j,1,b){
38         l=1; r=0;
39         inc(i,1,n){while(r>=l&&minh[i][j]<q1[r])r--; q1[++r]=minh[i][j]; q2[r]=i;} minl[1][j]=q1[l];
40         inc(i,n+1,a){
41             if(i-n>=q2[l])l++; while(r>=l&&minh[i][j]<q1[r])r--;
42             q1[++r]=minh[i][j]; q2[r]=i; minl[i-n+1][j]=q1[l];
43         }
44     }
45     ans=INF;
46     inc(i,1,a-n+1)inc(j,1,b-n+1){
47         ans=min(ans,maxl[i][j]-minl[i][j]);
48     }
49     printf("%d",ans); return 0;
50 }

题解:做4次单调队列。先利用单调队列求出第i行第j列到第i行第j+n-1列的最大最小值,再利用这个求出第i行第j列到第i+n-1行第j+n-1列的最大最小值。最后枚举一下求最小的差就行了。

吐槽:本蒟蒻单调队列开始各种符号写反,比如判断是否要l++的那个条件。以及因为INF设得太小WA了一发,拍都拍不出,最后改成2147483647乱交一发结果过了。

7、bzoj1927 http://www.lydsy.。com/JudgeOnline/problem.php?id=1927

题意:赛车大赛的赛场由N颗行星和M条双向星际航路构成,其中每颗行星都有一个不同的引力值。大赛要求车手们从一颗与这N颗行星之间没有任何航路的天体出发,访问这N颗行星每颗恰好一次。赛车超能电驴在高速航行模式下,沿星际航路航行,但只能由每个星球飞往引力比它大的星球。在能力爆发模式下,超能电驴在经过一段时间的定位之后,能瞬间移动到任意一个行星。求完成比赛最短时间。N≤800,M≤15000

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 #define maxn 2000
 7 #define INF 0x3fffffff
 8 using namespace std;
 9
10 struct e{int f,t,c,w,n;}; e es[maxn*40]; int ess,g[maxn];
11 inline void pe(int f,int t,int c,int w){
12     es[++ess]=(e){f,t,c,w,g[f]}; g[f]=ess; es[++ess]=(e){t,f,0,-w,g[t]}; g[t]=ess;
13 }
14 void init(){ess=-1; memset(g,-1,sizeof(g));}
15 int d[maxn],fr[maxn]; bool inq[maxn]; queue <int> q;
16 bool spfa(int s,int t){
17     while(!q.empty())q.pop(); memset(inq,0,sizeof(inq)); memset(d,-1,sizeof(d));
18     inq[s]=1; d[s]=0; q.push(s); fr[s]=-1;
19     while(! q.empty()){
20         int x=q.front(); q.pop(); inq[x]=0;
21         for(int i=g[x];i!=-1;i=es[i].n)if(es[i].c&&(d[es[i].t]==-1||d[es[i].t]>d[x]+es[i].w)){
22             d[es[i].t]=d[x]+es[i].w; fr[es[i].t]=i; if(!inq[es[i].t])inq[es[i].t]=1,q.push(es[i].t);
23         }
24     }
25     return d[t]!=-1;
26 }
27 int advanced(int s,int t){
28     int a=INF,c=0;
29     for(int i=fr[t];i!=-1;i=fr[es[i].f])a=min(a,es[i].c);
30     for(int i=fr[t];i!=-1;i=fr[es[i].f])es[i].c-=a,es[i^1].c+=a,c+=(a*es[i].w);
31     return c;
32 }
33 int maxflowmincost(int s,int t){
34     int c=0; while(spfa(s,t))c+=advanced(s,t); return c;
35 }
36 int n,m,s,t;
37 int main(){
38     scanf("%d%d",&n,&m); s=0; t=2*n+1; init();
39     inc(i,1,n){int a; scanf("%d",&a); pe(s,i+n,1,a);}
40     inc(i,1,m){int a,b,c; scanf("%d%d%d",&a,&b,&c); pe(min(a,b),max(a,b)+n,1,c);}
41     inc(i,1,n)pe(s,i,1,0),pe(i+n,t,1,0);
42     printf("%d",maxflowmincost(s,t)); return 0;
43 }

题解:费用流。对每个点拆成X,Y两个点,源向每个Y点连边,流量为1,费用为对这个行星的定位时间,表示直接经过这个行星。源再向每个X点连边流量1,费用0,每个Y点向汇连边,流量1,费用0。X与Y之间按“星际航路”连边,表示从X点到Y点。我们不关心从哪里到这个行星再到哪里去,我们只考虑每个行星只能经过一次。

吐槽:本智障一开始看不懂任何题解,后来发现自己以为是能力爆发模式需要受引力限制,不审题退役QAQ

时间: 2024-10-15 11:25:49

20160522~20160528的相关文章

第二期冲刺每日站立会议——20160528

一.站立会议信息 第二期团队的冲刺阶段第一天. 在今天的站立会议上,小组成员对于每个人的进度进行了说明.我们最近两三天正在进行的任务是修改第一阶段的BUG.搜集相关资料.并逐步开始第二阶段任务. 有图有真相: 二.任务进度 由于昨天课少,小组成员均或多或少的开始了第二期任务.相信接下来,我们能够更加积极的面对第二期团队冲刺. ╭(′▽`)╭(′▽`)╯<( ̄︶ ̄)[GO!] 三.任务看板图 四.燃尽图

每天刷个算法题20160522:支持各种类型的并查集

版权所有.所有权利保留. 欢迎转载,转载时请注明出处: http://blog.csdn.net/xiaofei_it/article/details/51524671 为了防止思维僵化,每天刷个算法题.已经刷了几天了,现在发点代码. 我已经建了一个开源项目,每天的题目都在里面: https://github.com/Xiaofei-it/Algorithms 绝大部分算法都是我自己写的,没有参考网上通用代码.读者可能会觉得有的代码晦涩难懂,因为那是我自己的理解. 最近几天都是在写一些原来的东西

用sql 生成2016年全年的日期

select to_char(日期,'yyyy-mm-dd') from( select to_date('2016-01-01','yyyy-mm-dd') + level 日期 from dual connect by level <=to_date('2016-12-31','yyyy-mm-dd')-to_date('2016-01-01','yyyy-mm-dd')); 结果: "日期""2016-01-02""2016-01-03&quo

iOS阳历转阴历的一个demo

最近项目开发过程中,涉及到阳历转阴历 于是自己写了一个 @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self test]; } - (NSString*)getLunarDateString:(NSDate*)date { static NSCalendar*lunarCalendar; static NSArray*lunarDateDescription; static NSArray*

用andtoid studio获取天气数据并解析适配

1.申请拿到数据 可以用“聚合数据” 2.在android studio中导入需要的jar包 复制—>app—>libs—>粘贴—>右击—>Add As Library……—>选择model—>ok 此项目所用的jar包建议: fastjson xUtils(访问部分可用异步任务jar包代替) 3.网络权限 <uses-permission android:name="android.permission.INTERNET"><

MS SQL Server 时间函数

日期和时间数据类型 数据类型 存储(字节) 日期范围 精确度 格式示例 DateTime 8 1753年1月1日 - 9999年12月31日 3 1/3毫秒 yyyy-MM-dd hh:mm:ss.nnn smalldatetime 4 1900年1月1日 - 2079年6月6日 1分钟 yyyy-MM-dd hh:mm date 3 0001年1月1日 - 9999月12月31日 1天 yyyy-MM-dd time 3-5 N/A 100纳秒 hh:mm:ss.nnnnnnn DateTim

本周学习进度5

发表日期 2016-05-22 本周学习进度如下: 所花时间(包括上课) 12Hours 代码量(行) 150 博客量(篇) 2 了解到的知识点 软件测试的主要内容:验证和确认 主要边界的确定.测试的不同分类如黑盒白盒.静态动态.单元.集成.确认.系统等

rhel7文件的归档与压缩

归档的好处 方便使用.查询.阅读 易于管理(批量操作文件) 文件压缩的好处 加快文件传输的速率 节约硬盘的资源 Linux文件中的文件归档与压缩 1.1 tar命令的使用 1.1.1 作用:打包.压缩文件 [[email protected] ~]# tar --help 用法: tar [选项...] [FILE]...  GNU 'tar' 将许多文件一起保存至一个单独的磁带或磁盘归档,并能从归档中单独还原所需文件. 示例   tar -cf archive.tar foo bar  # 从

利用MySQL官方源安装5.6版程序,以及降级安装后无法启动的问题

前两天安装MySQL,用的是官方的yum源安装,安装好后发现 5.7版本内存占用还蛮高的,默认5.6版安装完成后启动占用内存大概400M+ ,5.7版本默认安装完成后内存占用竟然占到800M+  简直翻了一倍. 可能5.7上有很多新功能和新特性,但是现阶段我觉得我还远用不到,那么就降级安装5.6版本的吧. 由于系统上已经有了官方 yum源的配置,那么就通过yum来安装5.6版本的MySQL吧. 这是官方mysql源的配置信息,可见已经有了5.5/5.6/5.7版本的源. 因为默认使用yum安装m