Gym101482 NWERC 2014(队内训练第4场)
-----------------------前面的两场感觉质量不高,就没写题解-----------------------------
A .Around the Track
pro:给定内多边形A和外多边形B,求最短路径,蛮子路径再A之外,B之内。
sol:如果没有B,就是求凸包,有了B,我们在做凸包的时候,有形如“a-b-c,b在内部,删去b,连接a-c的操作”,如果a-c和B不相交,直接删去b,否则用B的凸包代替b处。
#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int, int> Point;
typedef long long LL;
const int maxn=;
bool operator != (Point b, Point c)
{
return (b.x!=c.x || b.y!=c.y);
}
double dis(Point b, Point c);
struct polygon
{
int n;
bool cannotdel[maxn];
Point p[maxn]; polygon():n(){} void read()
{
scanf("%d", &n);
for (int i=; i<=n; ++i)
scanf("%d%d", &p[i].x, &p[i].y);
p[]=p[n];
p[n+]=p[];
for (int i=; i<=n; ++i) cannotdel[i]=false;
} double track()
{
double ans=;
for (int i=; i<=n; ++i)
ans+=dis(p[i], p[i+]);
return ans;
} void del(int pos)
{
for (int i=pos; i<n; ++i)
{
p[i]=p[i+];
cannotdel[i]=cannotdel[i+];
}
--n;
p[n+]=p[];
p[]=p[n];
} void insert(int posl, int posr, vector<Point> &newp)
{
int m=posl+n-posr++newp.size();
for (int i=; i<(n-posr+); ++i)
{
p[m-i]=p[n-i];
cannotdel[m-i]=cannotdel[n-i];
}
n=m; m=newp.size();
for (int i=; i<m; ++i)
{
p[posl++i]=newp[i];
cannotdel[posl++i]=true;
}
p[n+]=p[];
p[]=p[n];
} void print()
{
puts("======================");
for (int i=; i<=n+; ++i)
printf("%d %d\n", p[i].x, p[i].y);
}
};
polygon inner, outer;
Point pp[maxn];
Point globalps;
set<Point> innerpoint;
vector<Point> newp;
inline LL sqr(LL x)
{
return x*x;
}
LL det(Point b, Point c, Point o)
{
return (b.x-o.x)*(c.y-o.y)-(b.y-o.y)*(c.x-o.x);
}
double dis(Point b, Point c)
{
return sqrt(sqr(b.x-c.x)+sqr(b.y-c.y));
}
LL sdis(Point b, Point c)
{
return (sqr(b.x-c.x)+sqr(b.y-c.y));
}
bool intriangle(Point &b, Point &c, Point &d, Point &o)
{
return (abs(det(b, c, o))+abs(det(b, d, o))+abs(det(c, d, o)))==abs(det(b, c, d));
}
bool cmp(Point b, Point c)
{
LL tmp=det(b, c, globalps);
if (tmp!=) return tmp<;
return sdis(b, globalps)<sdis(c, globalps);
}
void convex(vector<Point> &p, Point &ps, Point &pf)
{
globalps=ps;
sort(p.begin(), p.end(), cmp);
int n=p.size();
for (int i=; i<=n; ++i) pp[i]=p[i-];
pp[++n]=pf;
pp[]=ps;
int m=;
for (int i=; i<=n; ++i)
{
while (m> && det(pp[i], pp[m], pp[m-])<) --m;
pp[++m]=pp[i];
}
p.resize(m-);
for (int i=; i<m; ++i) p[i-]=pp[i];
}
void solve()
{
for (int i=; i<=inner.n; ++i)
innerpoint.insert(inner.p[i]); while ()
{
bool flag=false;
for (int i=; i<=inner.n; ++i)
if (!inner.cannotdel[i] && det(inner.p[i+], inner.p[i-], inner.p[i])<)
{
newp.clear();
for (int j=; j<=outer.n; ++j)
if (intriangle(inner.p[i-], inner.p[i], inner.p[i+], outer.p[j]))
if (innerpoint.count(outer.p[j])==)
newp.push_back(outer.p[j]); for (int j=; j<=inner.n; ++j)
if (inner.p[j]!=inner.p[i-] && inner.p[j]!=inner.p[i] && inner.p[j]!=inner.p[i+]
&& intriangle(inner.p[i-], inner.p[i], inner.p[i+], inner.p[j]))
newp.push_back(inner.p[j]); if (newp.size()==) { flag=true; inner.del(i); break; }
convex(newp, inner.p[i-], inner.p[i+]); flag=true;
for (auto &p:newp)
if (innerpoint.count(p)) { flag=false; break; } if (!flag) continue;
for (auto &p:newp) innerpoint.insert(p);
inner.insert(i-, i+, newp);
}
if (!flag) break;
}
printf("%.7lf\n", inner.track());
}
int main()
{
inner.read();
outer.read();
solve();
return ;
}
B .Biking Duck
pro:给定二维平面,已知有N个位置有自行车站,以及地图边界都是自行车站,自行车可以从一个站到另一个站。在地图上走路或者骑自行车都是走直线。给定终点起点,求从从起点到终点的最小时间。
sol:路径不可能是曲曲折折的,这样性价比不高。 只有几种情况:
1:骑车可能要绕路,没必要骑车, 直接走路,起点->终点。
2:骑一次,起点走路->到站->到站->走路到终点。
而骑车要考虑边界上的车站,我们可以利用对称的知识,知道以边界为直线对称后,两点间直线最短,与对称轴的交点,是凹函数的分界线,这个可以用三分求。
...写起来应该很烦,告辞。
C .Cent Savings
pro:按顺序给定N个商品,相邻的可以分到同一组,你可以最多分成D+1组,每一组的价格四舍五入,求最小价格。N<2e3,D<20;
sol:由于的相邻的分组,就DP即可,O(N^2*D)。 单调队列优化O(N*D);
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
int dp[maxn][];//dp[i][j]
int a[maxn], sum[maxn];
inline f(int x){return (x / * + (x % <= ? : ));}
int main()
{
int n, d;
cin >> n >> d;
for(int i = ; i <= n; i++)cin >> a[i], sum[i] = a[i] + sum[i - ];
for(int i = ; i <= n; i++)dp[i][] = f(sum[i]);
for(int j = ; j <= d + ; j++)
{
for(int i = j; i <= n; i++)
{
int tmp = 1e9 + ;
for(int k = j - ; k <= i - ; k++)
{
tmp = min(tmp, dp[k][j - ] + f(sum[i] - sum[k]));
}
dp[i][j] = tmp;
}
}
int ans = 1e9 + ;
for(int i = ; i <= d + && i <= n; i++)ans = min(ans, dp[n][i]);
cout<<ans<<endl;
return ;
}
D .Digi Comp II
pro:给定M个开关,每个开关有初始状态(L或者R),每个开关有两个走向,分别指向左边对应的开关和右边对应的开关。 一个球走到当前开关,会走向当前状态指向的方向,并且使当前的状态改变。 问N个球从1号出发,最终每个开关的状态。 给定的关系是个DAG,除了0号都有两个出度,可以看成左右儿子。
sol:模拟一下,不难发现,如果X个球经过i节点,那么将会有X/2+X&1次走向初始方向,X/2次走向另外一个方向。即是topo排序一下可以搞。
这题WA的蛮多的,有两个注意;
1:不一定只要1号点入度为0,题目只保证了除0之外,出度为2;没保证入度(这一点感觉题目的确误导了很多读题人)。 所以必须开始把入度为0的都加进queue去,不然有的点跑不到。
2:左右儿子一样的情况下,如果先减左右儿子的入度,再入队,会加两次,导致错误。
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
int ind[maxn],ans[maxn];
int a[maxn],b[maxn],q[maxn],head,tail;
ll Now[maxn],N; char c[maxn][];
int main()
{
int M,u,v;
scanf("%lld%d",&N,&M);
rep(i,,M){
scanf("%s%d%d",c[i],&a[i],&b[i]);
ind[a[i]]++; ind[b[i]]++;
}
Now[]=N; rep(i,,M) if(!ind[i]) q[++head]=i;
while(tail<head){
u=q[++tail];
if(u==) break;
if(Now[u]%==) ans[u]=;
if(c[u][]=='L'){
Now[a[u]]+=(Now[u]-Now[u]/);
Now[b[u]]+=Now[u]/;
}
else {
Now[b[u]]+=(Now[u]-Now[u]/);
Now[a[u]]+=Now[u]/;
}
ind[a[u]]--;
if(ind[a[u]]==) q[++head]=a[u];
ind[b[u]]--;
if(ind[b[u]]==) q[++head]=b[u];
}
rep(i,,M) {
if(ans[i]) {
if(c[i][]=='L') putchar('R');
else putchar('L');
}
else {
if(c[i][]=='R') putchar('R');
else putchar('L');
}
}
return ;
}
E :Euclidean TSP
pro:虽然题目是TSP,但是和TSP没什么大关系。 就是给定飞机上升的时间和直线飞行的时间,二者和C的关系,求最小时间。
sol:飞机飞高需要时间,飞高之后飞得快,不难想到总时间随高度先增后减,三分即可。
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
double n, p, s, v;
const double eps = 1e9;
const double t = sqrt(2.0);
double f(double x)
{
double tmp = n * pow(log(n) / log(2.0), t * x);
tmp = tmp /(eps * p);
tmp = tmp + s / v * (x + 1.0) / x;
return tmp;
}
int main(){
cin >> n >> p >> s >> v;
double l =, r = , ans=1e60, c;
int T = ;
while(T--)
{
double lmid = l + (r - l) / 3.0;
double rmid = r - (r - l) / 3.0;
double Lans=f(lmid),Rans=f(rmid);
if(Rans> Lans){
r=rmid;
if(ans>Lans) ans =Lans, c = lmid;
}
else{
l = lmid;
if(ans>Rans) ans =Rans, c = rmid;
}
}
printf("%.9f %.9f\n", ans, c);
return ;
}
F .Finding Lines
pro:给定N个点,P; 问是否有超过P%的点在一条直线上。
sol:随机两个点,看多少点在直线上。(上海大都会原题)
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn = 1e5 + ;
struct node
{
ll x, y;
}c[maxn];
node a, b;
bool judge(node c)
{
return (b.y - a.y) * (c.x - b.x) == (b.x - a.x) * (c.y - b.y);
}
int main()
{
srand(time());
int n, p;
cin >> n >> p;
for(int i = ; i <= n; i++)cin >> c[i].x >> c[i].y;
if(n <= )
{
cout<<"possible\n";
return ;
}
int T = ;
bool flag = ;
while(T--)
{
int x = (ll)rand() * rand() % n + ;
int y = (ll)rand() * rand() % n + ;
if(x == y)continue;
a = c[x], b= c[y];
int tot = ;
for(int i = ; i <= n; i++)if(judge(c[i]))tot++;
if(1.0 * tot / n + 1e- >= 0.01 * p){flag = ;break;}
}
if(flag)cout<<"possible"<<endl;
else cout<<"impossible"<<endl;
return ;
}
G .Gathering
pro:给定二维平面上N个点,以及D。要求找一个点X,满足X到N个点的曼哈顿距离都不超过D,而总距离最小。 不存在合法的输出"impossible"
sol:因为我们知道中位数这个位置比较关键,X和Y可以分开考虑,分别是取中位数时最小,对X和Y都是凹函数。
比赛的时候大方向想对了。大概是曼哈顿距离转化切比雪夫,然后套二分或者三分。 (但是居然求公共矩形不会了。。。赛后想不就是对R和U取min,对取L和U取max吗。。。 然后我们在合法的多边形里三分套三分即可。 也可以三分之后直接找最接近中位数的Y即可。
曼哈顿转切比雪夫: 原点A(X,Y)---->逆时针旋转45度后,长度*sqrt2的点A‘(X+Y,X-Y);
切比雪夫转曼哈顿: L<=x<=R ; D<=y<=U ; 现在:(L+D)/2<=x<=(R+U)/2,且x一定时满足,L<=x+y<=R,D<=y<=U;
三分套三分:O(N(log1e9)^2~=9e7),会超时T37.
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
const ll inf=1e30;
ll x[maxn],y[maxn],D,ans=1e30,midy;
ll up=inf,dn=-inf,le=-inf,ri=inf; int N;
ll solvey(ll midx,ll Y)
{
ll res=;
rep(i,,N) res+=abs(midx-x[i])+abs(Y-y[i]);
return res;
}
ll solvex(ll midx)
{
ll yu=min(midx-dn,ri-midx);
ll yd=max(midx-up,le-midx);
if(yu<yd) return inf;
ll res=inf,mid;
while(yd<yu-){
ll l=yd+(yu-yd)/,ans1=solvey(midx,l);
ll r=yu-(yu-yd)/,ans2=solvey(midx,r);
if(ans1>ans2) yd=l,res=min(res,ans2);
else yu=r,res=min(res,ans1);
}
rep(i,yd,yu) res=min(res,solvey(midx,i));
return res;
}
int main()
{
scanf("%d",&N);
rep(i,,N) scanf("%lld%lld",&x[i],&y[i]);
scanf("%lld",&D);
rep(i,,N){
dn=max(dn,x[i]-y[i]-D);
up=min(up,x[i]-y[i]+D);
le=max(le,x[i]+y[i]-D);
ri=min(ri,x[i]+y[i]+D);
}
if(dn>up||le>ri) return puts("impossible"),;
sort(y+,y+N+); midy=(y[(N+)/]);
ll L=(le+dn)/,R=(up+ri)/;
while(L<R-){
ll l=L+(R-L)/,ans1=solvex(l);
ll r=R-(R-L)/,ans2=solvex(r);
if(ans1>ans2) L=l,ans=min(ans,ans2);
else R=r,ans=min(ans,ans1);
}
rep(i,L,R) ans=min(ans,solvex(i));
printf("%lld\n",ans);
return ;
}
三分+中位数逼近:没必要取三分y,直接用结论即可,取靠近y[]的中位数。
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
const ll inf=1e30;
ll x[maxn],y[maxn],D,ans=1e30,midy;
ll up=inf,dn=-inf,le=-inf,ri=inf; int N;
ll solve(ll midx)
{
ll yu=min(midx-dn,ri-midx);
ll yd=max(midx-up,le-midx);
if(yu<yd) return inf;
ll Y,res=;
rep(i,,N) res+=abs(midx-x[i])+abs(Y-y[i]);
return res;
}
int main()
{
scanf("%d",&N);
rep(i,,N) scanf("%lld%lld",&x[i],&y[i]);
scanf("%lld",&D);
rep(i,,N){
dn=max(dn,x[i]-y[i]-D);
up=min(up,x[i]-y[i]+D);
le=max(le,x[i]+y[i]-D);
ri=min(ri,x[i]+y[i]+D);
}
if(dn>up||le>ri) return puts("impossible"),;
sort(y+,y+N+); midy=(y[(N+)/]);
ll L=(le+dn)/,R=(up+ri)/;
while(L<R-){
ll l=L+(R-L)/,ans1=solve(l);
ll r=R-(R-L)/,ans2=solve(r);
if(ans1>ans2) L=l,ans=min(ans,ans2);
else R=r,ans=min(ans,ans1);
}
rep(i,L,R) ans=min(ans,solve(i));
printf("%lld\n",ans);
return ;
}
H .Hyacinth
pro:看不懂。
sol:by队友
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
struct edge{
int d,nex;
}e[];
struct node{
int x,y;
bool a,b;
}a[];
int q[],efree,n,cnt;
inline void add(int x,int y){e[++efree]=(edge){y,q[x]},q[x]=efree;}
void dfs(int x,int y){
if(a[x].a==)a[x].x=++cnt;
if(a[x].b==)a[x].y=++cnt;
int v=q[x];while(e[v].d==y)v=e[v].nex;
if(!v)return;
if(a[x].a)a[e[v].d].x=a[x].y,a[e[v].d].a=a[x].b=;
else a[e[v].d].x=a[x].x,a[e[v].d].a=a[x].a=;
dfs(e[v].d,x);
for(int i=e[v].nex;i;i=e[i].nex)
if(e[i].d!=y){
if(a[x].a)a[e[i].d].x=a[x].y,a[e[i].d].a=a[x].b=;
else a[e[i].d].x=a[x].x,a[e[i].d].a=a[x].a=;
dfs(e[i].d,x);
}
}
int main(){
scanf("%d",&n);
if(n==){
puts("1 2");
puts("2 1");
return ;
}
for(int i=;i<n;i++){
int x,y;scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs(,);
for(int i=;i<=n;i++)printf("%d %d\n",a[i].x,a[i].y);
return ;
}
I. Indoorienteering
题意:找长度为L的哈密尔顿回路,N<=14;
思路:N!太大,我们可以折半枚举
J .Judging Troubles
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
map<string, int>Map1, Map2;
int main()
{
int n, ans = ;
string s;
cin >> n;
for(int i = ; i <= n; i++)cin >> s, Map1[s]++;
for(int i = ; i <= n; i++)cin >> s, Map2[s]++;
for(map<string, int>::iterator it = Map1.begin(); it != Map1.end(); it++)
ans += min(Map1[it->first], Map2[it->first]);
cout<<ans<<endl;
return ;
}
Knapsack Collection
队友写了,但是代码没给我啊。。。
Gym101482 NWERC 2014(队内训练第4场)的更多相关文章
- hdu 4911 Inversion(归并排序求逆序对数)2014多校训练第5场
Inversion Time Limit: 20 ...
- hdu 4970 Killing Monsters(数组的巧妙运用) 2014多校训练第9场
pid=4970">Killing Monsters ...
- 2014暑假ACM训练总结
2014暑假ACM训练总结报告 匆匆之中,一个暑假又过去了,在学校训练的这段日子真的是感觉日子过得好快啊! 时光如箭,日月如梭! 匆忙的学习之中一个暑假就这样结束了,现在就来写一些总结吧,供自己以后阅 ...
- Contest1592 - 2018-2019赛季多校联合新生训练赛第二场(部分题解)
Contest1592 - 2018-2019赛季多校联合新生训练赛第二场 D 10248 修建高楼(模拟优化) H 10252 组装玩具(贪心+二分) D 传送门 题干 题目描述 C 市有一条东西走 ...
- Contest1585 - 2018-2019赛季多校联合新生训练赛第一场(部分题解)
Contest1585 - 2018-2019赛季多校联合新生训练赛第一场 C 10187 查找特定的合数 D 10188 传话游戏 H 10192 扫雷游戏 C 传送门 题干: 题目描述 自然数中除 ...
- HDU6578 2019HDU多校训练赛第一场 1001 (dp)
HDU6578 2019HDU多校训练赛第一场 1001 (dp) 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6578 题意: 你有n个空需要去填,有 ...
- HDU6621 K-th Closest Distance HDU2019多校训练第四场 1008(主席树+二分)
HDU6621 K-th Closest Distance HDU2019多校训练第四场 1008(主席树+二分) 传送门:http://acm.hdu.edu.cn/showproblem.php? ...
- 2014百度之星预赛(第二场)——Best Financing
2014百度之星预赛(第二场)--Best Financing Problem Description 小A想通过合理投资银行理財产品达到收益最大化.已知小A在未来一段时间中的收入情况,描写叙述为两个 ...
- 山东省ACM多校联盟省赛个人训练第六场 poj 3335 D Rotating Scoreboard
山东省ACM多校联盟省赛个人训练第六场 D Rotating Scoreboard https://vjudge.net/problem/POJ-3335 时间限制:C/C++ 1秒,其他语言2秒 空 ...
随机推荐
- Python学习之路【第二篇】-pyc简介、Python常用的数据类型及其用法和常用运算符
1.pyc简介 python程序在运行时也有编译过程,编译后会产生.pyc文件.这是一种由python虚拟机执行的二进制文件(字节码),用于保存内存中PyCodeObject,以便加快程序的加载运行. ...
- 我个人对OOP的理解
OOP面向对象的思维:pay1:封装 A.避免使用非法数据赋值 B.保证数据的完整性 C.避免类内部发生修改的时候,导致整个程序的修改 pay2:继承 A.继承模拟了现实世界的关系,OOP中强调一切皆 ...
- linux nat style
1● nat style 2● link style
- jquery 共用函数
ready()方法 $(doxument).ready(fucntion(){ }) $().ready(function(){ }) $(function(){ }) 当文档加载后激活函数: ...
- 如何破解Visual studio 2013
1.打开VS2013点击菜单栏中的帮助,选择注册产品. 2.如下图所示,你就可以看到你的VS是不是试用版了,很显然,现在我的还是试用版,还有20天的使用期限. 3.如下图所示,点击更改我的产品许可证. ...
- js判断一个值是空的最快方法是不是if(!value){alert("这个变量的值是null");}
!逻辑非 操作符(js)-操作于任何值,(!undefined)(!Null)(!任何对象)(!"")(!"lihuan")(!任何非零数字值) (!0)(!N ...
- Java多线程习题 ===重点 ,错题积累
多线程重点,错题分析 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: . 12: 13: 14: 15:
- 依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI)
原文: https://blog.csdn.net/briblue/article/details/75093382 写这篇文章的原因是这两天在编写关于 Dagger2 主题的博文时,花了大量的精力来 ...
- python列表、集合、元祖、字典推导式
a = [1, 2, 3, 4, 5, 6, 7, 8]l=[i**2 for i in a if i**2>=16] #列表推导式+if判断print(l)print(type(l)) b={ ...
- JSON转化
相关链接 : http://blog.csdn.net/gchb9527/article/details/8688279 --------------------------------------- ...