Time:2018.4.29 8:30-13:30
A
题意
给出总的路程L,普通速度a,喝咖啡速度后b,等咖啡时间t,咖啡有作用时间r,和n个咖啡厅的位置。买咖啡需要等待,喝咖啡时速度提升
问在哪几个咖啡厅买咖啡,走完总路程所花的时间最短。可以扔掉咖啡,可以用手机预定咖啡。(L<=1e11,a,b<=200,t<=300,r<=1200,n<=5e5)
假如不可以预定怎么做?
分析
Difficult
ym:单调队列优化后dp???,留坑
B solved by ym
题意
四人接力跑,现分别给出n个人的第一棒和其他棒的时间,问选择四个人所用时间最小的时间,和对应的人(即方案) (n<=500)
分析
ym:首先直观的n^4暴力枚举,肯定不行,枚举第一棒贪心选取其余的即可
时间复杂度O(nlogn)
C
题意
分析
大大大模拟,留坑
D solved by ym&czh
题意
给出n个长度为m的0/1串,0和0或者1和1都是相同,问找出一个字符串使得与其他所有串相同的的最多的最少(n<=1e5,m<=20)
分析
ym:相同的数量尽可能少==不同的数量尽可能多,故可以将每个串看做一个点出发从其BFS找所有没有出现过的点,找一个different最大
为什么different最大的是答案?我们BFS找到的每一个点都是原来的点最小different
时间复杂度:O(k*2^k)
czh:将每种字符串看作是一个点,总共2^20=1e6个点,以输入的n个字符串为起点,bfs找到最远的点
这题用了个sting加map,运算起来特别慢,以后要首先分析时间复杂度
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <iostream>
#include <cmath>
#include <queue>
#include <ctime>
using namespace std;
#define lson l,(l+r)/2,rt<<1
#define rson (l+r)/2+1,r,rt<<1|1
#define dbg(x) cout<<#x<<" = "<< (x)<< endl
#define pb push_back
#define fi first
#define se second
#define ll long long
#define sz(x) (int)(x).size()
#define pll pair<long long,long long>
#define pii pair<int,int>
#define pq priority_queue
int d[1<<20];
queue<int>q;
int n,k;
void bfs()
{
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=0;i<k;i++)
{
int v=u^(1<<i);
if(d[v]>d[u]+1)
{
d[v]=d[u]+1;
q.push(v);
}
}
}
}
int main()
{
string s;
cin>>n>>k;
for(int i=0;i<(1<<20);i++)
d[i]=1<<20+1;
for(int i=1;i<=n;i++)
{
cin>>s;
int sum=0;
for(int ii=0;ii<k;ii++)
{
if(s[ii]=='1')
sum+=(1<<(k-ii-1));
}
d[sum]=0;
q.push(sum);
}
bfs();
int id=0;
for(int i=0;i<(1<<k);i++)
{
if(d[i]>d[id])
{
id=i;
}
}
for(int i=0;i<k;i++)
{
if((id>>(k-i-1))&1)
cout<<1;
else
cout<<0;
}
cout<<endl;
return 0;
}
E solved by ym&czh
题意
n*m 的地方,每个地方给出高度,所有 n*m 的地方有海拔为 0 的积水。 现在给出一个点作为排水口,每个地方的水可以往周围八个方向,且比它低的地方流。问最后会流走多少水
分析
ym:从排水口出发BFS,排水口是终点,每一个点每次只要可以进行类似松弛操作就update,但不幸,TEL,因为一个点可能被update很多次并且每次update后都要从其出发继续update
优化:一个较为显然的是,每次从较低的从出发update最优,思想类似最短路,每次从边权最小的出发
裸的BFS找最短路适用于边权都一样的,才能保证复杂度为O(v+e),因为每个点只会访问一次(第一次访问的一定是最小的),回到此题,高度和边权类似,但“边权”不一样
所以时间复杂度会爆炸
时间复杂度(nlogn)
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int mod=1e9+7;
const int dx[]={1,-1,0,0,1,1,-1,-1};
const int dy[]={0,0,-1,1,-1,1,1,-1};
int mp[505][505];
int h,w,ans[505][505];
int sx,sy;
struct node
{
int x,y,h;
friend bool operator<(node a,node b)
{
return a.h>b.h;
}
};
bool ok(int x,int y)
{
if(x>=1&&x<=h&&y>=1&&y<=w)
return true;
return false;
}
void bfs(int x,int y,int h)
{
priority_queue<node>q;
q.push({x,y,h});
while(!q.empty())
{
node k=q.top();
q.pop();
for(int i=0;i<8;i++)
{
int xx=k.x+dx[i];
int yy=k.y+dy[i];
if(ok(xx,yy) && ans[xx][yy]>max(k.h,mp[xx][yy]))
{
ans[xx][yy]=max(k.h,mp[xx][yy]);
q.push({xx,yy,ans[xx][yy]});
}
}
}
}
int main()
{
scanf("%d%d",&h,&w);
for(int i=1;i<=h;i++)
{
for(int j=1;j<=w;j++)
{
scanf("%d",&mp[i][j]);
if(mp[i][j]>0)
mp[i][j]=0;
}
}
scanf("%d%d",&sx,&sy);
if(mp[sx][sy]==0)
{
cout<<0<<endl;
return 0;
}
ans[sx][sy]=mp[sx][sy];
bfs(sx,sy,mp[sx][sy]);
ll answer=0;
for(int i=1;i<=h;i++)
{
for(int j=1;j<=w;j++)
{
answer+=ans[i][j];
}
}
cout<<-answer<<endl;
return 0;
}
F
Different
G solved by czh&ym
题意
有n个队伍,m条事件。每条事件代表a队伍通过一个题目,罚时为b。对于每条事件,输出,1号队伍的排名。
分析
czh:用一个set数组储存每个过题数的队伍编号。对于每次询问,如果不是一号队伍,只需要挪动set中的元素,如果是一号队伍,统计这次过题超过的队伍数,并挪动
ym:写了暴力复杂度爆炸成功TLE,还好帮忙czh找出错误样例
花絮:tm不能当变量名啊!!!
时间复杂度:由于和1同题数最多的队伍很多,并且修改的是1后就不想同的,所以很快(我算不出qaq)
H
题意
分析
ym:听说是极角排序后最大流,滚去学
I solved by ym
题意
问题可以简化为:给出n个点的有向图,问最小环的路径(即方案)(n<=500)
分析
ym:dfs标记找环??X掉) 从每个点出发BFS,求出最短路的过程中记录前驱即可,既然都是环,随便输出都行 / 当然Floyd也可以
dfs找环存在的问题:由于序号标记是按照dfs顺序,故无法得出环的边数,但可以求是否存在环
时间复杂度O(n*(n+m))
#include<bits/stdc++.h>
using namespace std;
vector<int>v[502],rv[502];
unordered_map<string,int>mp;
int d[502];
int pre[502];
char name[502][10];
void bfs(int st)
{
queue<int>q;
q.push(st);
d[st]=0;
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=0;i<int(v[now].size());i++)
{
int to=v[now][i];
if(d[to]>d[now]+1)
{
d[to]=d[now]+1;
pre[to]=now;
q.push(to);
}
}
}
}
int main()
{
int n;
string s;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",name[i]);
mp[name[i]]=i;
}
int x=n,k;
while(x--)
{
cin>>s;
scanf("%d",&k);
int u=mp[s];
while(k--)
{
cin>>s;
while(1)
{
cin>>s;
int len=s.length();
if(s[len-1]==',')
{
s.resize(len-1);
int to=mp[s];
v[to].push_back(u);
rv[u].push_back(to);
}
else
{
int to=mp[s];
v[to].push_back(u);
rv[u].push_back(to);
break;
}
}
}
}
int ans=1e9,st,ed;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
d[j]=1e9;
bfs(i);
for(int j=0;j<int(rv[i].size());j++)
{
int u=rv[i][j];
if(ans>d[u]+1)
{
ans=d[u]+1;
st=i;
ed=u;
}
}
}
if(ans==1e9)
{
puts("SHIP IT");
return 0;
}
else
{
for(int j=1;j<=n;j++)
d[j]=1e9;
bfs(st);
int now=ed;
while(now!=st)
{
printf("%s ",name[now]);
now=pre[now];
}
printf("%s
",name[now]);
}
return 0;
}
J solved by ym
题意
签到,按题意模拟即可
K solved by ym
题意
给出三种人的数量b,n,e,每种人有一个Sb,Sn,Se,现两人一组,给出(b+n+e)/2个vi,问要所有组最小的最大方案,输出最小的最大
分析
ym:二分答案后贪心暴力check
时间复杂度O(nlogn)
#include<bits/stdc++.h>
using namespace std;
int B,N,E;
int a[1000005],w[5],m[5];
int sb,sn,se,n;
bool check(int mid)
{
int mm[5];
mm[1]=m[1], mm[2]=m[2], mm[3]=m[3];
for(int i=1;i<=n;i++)
{
int jj=-1,kk=-1;
int need=mid/a[i]+(mid%a[i]>0);
for(int j=1;j<=3;j++)
{
for(int k=j;k<=3;k++)
{
int num=1;
if(j==k) num=2;
if(jj==-1&&kk==-1)
{
if(mm[j]>=num && mm[k]>=num && (w[j]+w[k])>=need)
{
jj=j;
kk=k;
}
}
else
{
if(mm[j]>=num && mm[k]>=num && (w[j]+w[k])>=need && (w[j]+w[k])<(w[jj]+w[kk]))
{
jj=j;
kk=k;
}
}
}
}
if(jj==-1)
return false;
mm[jj]-=1;
mm[kk]-=1;
}
return true;
}
int main()
{
scanf("%d%d%d",&m[1],&m[2],&m[3]);
scanf("%d%d%d",&w[1],&w[2],&w[3]);
n=(m[1]+m[2]+m[3])/2;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
int l=1,r=1e9;
while(l<r)
{
int mid=(l+r+1)>>1;
if(check(mid)) l=mid;
else r=mid-1;
}
printf("%d
", l);
return 0;
}
Summary
Ym:
Czh: