2014 Benelux Algorithm Programming Contest (BAPC 14)
算5题?嘻嘻
Gym - 101512B Button Bashing
水题
#include<bits/stdc++.h>
using namespace std;
const int maxn=7206;
const int inf=0x3f3f3f3f;
int t[maxn],d[2*maxn];
int main()
{
int n,m,T;
cin>>T;
while(T--){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",t+i);
queue<int>q;
pair<int,int> ans=make_pair(inf,inf);
memset(d,0x3f,sizeof d);
d[0]=0,q.push(0);
while(!q.empty()){
int nd=q.front();
q.pop();
if(nd>=m)ans=min(ans,make_pair(nd,d[nd]));
for(int i=1;i<=n;i++){
int u=nd+t[i];
if(u<0)u=0;
if(u>3600)u=3600;
if(d[u]==inf)
d[u]=d[nd]+1,q.push(u);
}
}
cout<<ans.second<<" "<<ans.first-m<<endl;
}
return 0;
}
Gym - 101512E Excellent Engineers
知道树状数组的我哭了起来。
按A维排序,在B处插入C的值,维护区间最小值。查询时看(1~B)的最小值,有比C小的就加一。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=2e5+5;
int n, maxVal;
struct Operation
{
int a, b, c, w;
int f;//ans
bool operator <(const Operation &r)const
{
//return a<r.a || (a==r.a&&b<r.b) || (a==r.a&&b==r.b&&c<r.c);
return (a==r.a&&b==r.b) ? c<r.c : (a==r.a ? b<r.b : a<r.a);
}
}a[MAXN], t[MAXN];
LL c[MAXN];
inline int lowbit(int x) { return x&-x; }
inline void add(int p, int v) { for(;p<=maxVal;p+=lowbit(p)) c[p]+=v; }
inline LL sum(int p)
{
LL re=0;
for(;p;p-=lowbit(p)) re+=c[p];
return re;
}
int ans[MAXN];
LL rres;
void CDQ(int l, int r)
{
if(l==r) return;
int mid=(l+r)>>1;
CDQ(l, mid);CDQ(mid+1, r);
int i=l, j=mid+1, p=l;
while(i<=mid||j<=r)
{
if(j>r||(i<=mid&&a[i].b<=a[j].b)) add(a[i].c, a[i].w), t[p++]=a[i++];
else a[j].w+=sum(a[j].c), t[p++]=a[j++];
}
for(int i=l;i<=mid;i++) add(a[i].c, -a[i].w);
for(int i=l;i<=r;i++) a[i]=t[i];
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%d", &n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i].a),scanf("%d",&a[i].b),scanf("%d",&a[i].c),a[i].w=1;
sort(a+1, a+1+n);
int p=1;
maxVal=MAXN-1;
rres=0;
CDQ(1, n);
for(int i=1;i<=n;i++)
if(a[i].w==1) rres++;
printf("%d\n",rres);
}
//system("pause");
}
Gym - 101512I Interesting Integers
数学题,at老谭
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL f[49];
LL e_gcd(LL a,LL b,LL &x,LL &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
LL ans=e_gcd(b,a%b,x,y);
LL temp=x;
x=y;
y=temp-a/b*y;
return ans;
}
int main()
{
f[1]=1,f[2]=1;
for(int i=3;i<=47;i++)
f[i]=f[i-1]+f[i-2];
int T;
LL n;
cin>>T;
while(T--){
cin>>n;
LL ansx,ansy;
ansx=n/2;
ansy=n-ansx;
for(int i=3;;i++){
if(f[i]>n)break;
LL x=-1,y=-1;
LL g=e_gcd(f[i-2],f[i-1],x,y);
if(n%g)continue;
x*=(n/g),y*=(n/g);
LL t=(y-x)/(f[i-2]+f[i-1]);
x=x+t*f[i-1];
y=y-t*f[i-2];
if(x>y){
x-=f[i-1];
y+=f[i-2];
}
if(x<=0 || y<=0)continue;
if(ansy>y){
ansy=y,ansx=x;
}
else if(ansy==y && ansx>x)
ansy=y,ansx=x;
}
printf("%I64d %I64d\n",ansx,ansy);
}
return 0;
}
这时我冲上去写了一发暴力的K,果然gg。。
Gym - 101512G Growling Gears
大水题,连精度都不卡,不知道为什么过的人巨少,可能这种训练赛大家都不削于做水题。。
就是给你一堆抛物线
y=−ax2+bx+c
,求最高点。直接顶点公式
4ac−b24a
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=2e5+5;
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int n;scanf("%d",&n);
double ma;int mai=1;
for(int i=1;i<=n;i++)
{
LL a,b,c;scanf("%I64d %I64d %I64d",&a,&b,&c);
double fz=-4*a*c-b*b;
double fm=-4*a;
if(i==1) ma=fz/fm;
else
{
if(ma<fz/fm)
{
ma=fz/fm;
mai=i;
}
}
}
printf("%d\n",mai);
}
//system("pause");
return 0;
}
在比赛临结束搞过了A。。
Gym - 101512A Avoiding the Apocalypse
网络流。。根lrj那个运送宇宙超级计算机一模一样。。按时间拆点,注意细节就好。
超级源向s的0时刻连容量g的边,表示0时刻初始人数是g。
每个点的时刻t要向t+1连边,容量无穷,表示可以原地不动。
然后每个医院的任何时刻都要向超级汇连边,表示一旦到医院就算流。
在按时间连其他边。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=2e5+5;
const int oo=0x3f3f3f3f;
struct Dinic
{
struct Edge{
int from, to, cap, flow;//cap容量 flow流量
Edge(){}
Edge(int u, int v, int c, int f){ from=u;to=v;cap=c;flow=f; }
};
vector<Edge> edges;//顺序的插入边
vector<int> G[MAXN];//保存边号
bool vis[MAXN];//BFS使用
int d[MAXN];
int cur[MAXN];
void init(int n)
{
for(int i=0;i<=n;i++) G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));//单向边第三个参数写0,双向边写cap
int t_m=edges.size();
G[from].push_back(t_m-2);
G[to].push_back(t_m-1);
}
bool BFS(int s, int t)
{
memset(vis, 0, sizeof(vis));
queue<int> Q;
Q.push(s);
d[s]=0;
vis[s]=1;
while(!Q.empty())
{
int x=Q.front();Q.pop();
for(int i=0;i<G[x].size();i++)
{
Edge& e=edges[G[x][i]];
if(!vis[e.to]&&e.cap>e.flow)//残量网络
{
vis[e.to]=1;
d[e.to]=d[x]+1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x, int a, int s, int t)
{
if(x==t||a==0) return a;
int flow=0, _f;
for(int& i=cur[x];i<G[x].size();i++)
{
Edge& e=edges[G[x][i]];
if(d[x]+1==d[e.to]&&(_f=DFS(e.to, min(a, e.cap-e.flow), s, t))>0)
{
e.flow+=_f;
edges[G[x][i]^1].flow-=_f;
flow+=_f;
a-=_f;
if(a==0) break;
}
}
return flow;
}
int Maxflow(int s, int t)
{
int flow=0;
while(BFS(s, t))
{
memset(cur, 0, sizeof(cur));
flow+=DFS(s, oo, s, t);
}
return flow;
}
}dinic;
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int n;scanf("%d",&n);
int s,g,k;scanf("%d%d%d",&s,&g,&k);
dinic.init(n*(k+1)+5);
int m;scanf("%d",&m);
int super_s=(k+1)*n+1;
int super_t=(k+1)*n+2;
dinic.AddEdge(super_s,s,g);
while(m--)
{
int tmp;
scanf("%d",&tmp);
for(int i=0;i<=k;i++)
dinic.AddEdge(tmp+n*i,super_t,g);
}
for(int i=1;i<=n;i++)
for(int j=0;j<k;j++)
{
dinic.AddEdge(i+n*j,i+n*(j+1),g);
}
int r;scanf("%d",&r);
for(int i=1;i<=r;i++)
{
int a,b,p,t;scanf("%d%d%d%d",&a,&b,&p,&t);
int tm=0;
while(tm+t<=k)
{
dinic.AddEdge(a+n*(tm),b+n*(tm+t),p);
tm++;
}
}
int res=dinic.Maxflow(super_s,super_t);
printf("%d\n",min(res,g));
}
//system("pause");
return 0;
}
开始赛后补题。。说实话感觉D也不难,要是我当时不写K的暴力或许就能出了。。
Gym - 101512D Dropping Directions
这题很蛇皮,样例巨难画。不过耐着心画下来,实际每个点度都是4。我们假设一个路标都不设置,从目标点开始搜索,那么会搜出两个欧拉回路。因为目标点度是4,一个入一个出,所以会有两个回路。模拟样例2和样例3(因为他俩图一样,省事),发现剩下的欧拉回路一个回路添一个路标就可以了,因为一个路标就可以让这条回路全指向通往目标点的回路。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=100007;
const int oo=0x3f3f3f3f;
int vis[MAXN][4];
int to[MAXN][4];
int go(int p,int f)
{
if(to[p][0]==f) {vis[p][0]=1,vis[p][2]=1;return to[p][2];}
if(to[p][1]==f) {vis[p][1]=1,vis[p][3]=1;return to[p][3];}
if(to[p][2]==f) {vis[p][2]=1,vis[p][0]=1;return to[p][0];}
if(to[p][3]==f) {vis[p][3]=1,vis[p][1]=1;return to[p][1];}
assert("No Way!");
}
queue<pair<int,int>> que;
void sousuo(int u,int i)
{
if(!vis[u][i])
{
int now=to[u][i],la=u;vis[u][i]=1;
while(1)
{
int v=go(now,la);
la=now,now=v;
if(now==u)
{
for(int j=0;j<4;j++)
if(to[u][j]==la) vis[u][j]=1;
break;
}
}
}
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
memset(vis,0,sizeof(vis));
int n,s;scanf("%d%d",&n,&s);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&to[i][0],&to[i][1],&to[i][2],&to[i][3]);
}
for(int i=0;i<4;i++)
if(!vis[s][i])
sousuo(s,i);
// for(int i=1;i<=n;i++)
// {
// printf("%d ",i);
// for(int j=0;j<4;j++)
// {
// printf("%d:%d ",to[i][j],vis[i][j]);
// }
// printf("\n");
// }
int cnt=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<4;j++)
{
if(!vis[i][j])
sousuo(i,j),cnt++;
}
}
printf("%d\n",cnt);
}
//system("pause");
return 0;
}
Gym - 101512C Citadel Construction
凸包的最大内接四边形,旋转卡壳法。代码太长了,不贴了。
Gym - 101512K Key to Knowledge
正解是折半搜索。用空间换时间,将前一半 215 的结果存到map里面,搜索后一半时去里面查找。
#include<bits/stdc++.h>
using namespace std;
string ans[15];
int grade[15];
map<string, pair<int, long long>> rec;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int t;
cin>>t;
while(t--)
{
int n, m;
cin>>n>>m;
rec.clear();
for(int i=1;i<=n;i++)
{
cin>>ans[i]>>grade[i];
}
int mid=m/2;
for(long long a=0;a<(1ll<<mid);a++)
{
string status="";
for(int i=1;i<=n;i++)
{
int p=0;
long long aa=a;
for(int j=0;j<mid;j++)
{
if((aa&1)==ans[i][j]-'0') p++;
aa>>=1;
}
int relase=grade[i]-p;
if(relase<0) break;
status+='0'+relase;
}
if(status.size()==n)
{
rec[status].first++;
rec[status].second=a;
}
}
long long solution=0;
long long left, right;
for(long long a=0;a<(1ll<<(m-mid));a++)
{
string status="";
for(int i=1;i<=n;i++)
{
int p=0;
long long aa=a;
for(int j=mid;j<m;j++)
{
int nb=ans[i][j]-'0';
if((aa&1)==nb) p++;
aa>>=1;
}
int relase=grade[i]-p;
if(relase<0) break;
status+='0'+p;
}
if(status.size()==n)
{
auto it=rec.find(status);
if(it!=rec.end())
{
solution+=it->second.first;
left=it->second.second;
right=a;
}
}
}
if(solution==1)
{
string ans="";
for(int i=0;i<mid;i++)
{
ans+='0'+(left&1);
left>>=1;
}
for(int i=mid;i<m;i++)
{
ans+='0'+(right&1);
right>>=1;
}
cout<<ans<<'\n';
}
else
{
cout<<solution<<" solutions\n";
}
}
return 0;
}
剩下的,J是个水题模拟,剩下两个没看,好像题解都没有。。。