首先说明: 题解都是从 wannafly里面得到的。 详情请关注微信公众号:WannaflyUnion
http://codeforces.com/problemset/problem/725/F
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<string.h>
using namespace std;
#define ll __int64
/*
分析:
先手: 对a: +a1-b2-(+a2-b1) = a1-a2 +b1-a2 a2-a1 +b2-b1
对b: +b1-a2 -(b2-a1) = a1-a2 +b1-b2 后手:a2-a1 +b2-b1
对每对照片分类:
1 a1<=b2 && b1<=a2, 双方都想要选择后手,且 如果先手都没有收益,那不会选
2
a1+b1<=a2+b2, 即对于该对照片,双方的后手收益都好于先手收益,
且必有a1>b2或b1>a2,即必有一方有正收益 ,如果不选则没收益,但先选仍有收益
3 对于剩下的物体 排除了废物品 和 后手有利物品
那么只剩下 先手有利的物品了?? 如果不仅让自己得分最多,且让对手最少
一开始想的是
a1-b2+a2-b1 = a1+a2 -(b1+b2) 。。。然后越想越复杂
然而看了题解,似乎我们只需要注意a1+b1 ,按这个来作为条件,这样子就完成了上面的要求。真是神奇!
还有个问题:
对于一对牌:
a1 b1
a2 b2
如果a 先手了,b不一定马上选b2 可以去选其他更有价值的,那么我们可以重新创建一对: a2 b2 0 0
*/
struct node{
int a1,b1,a2,b2;
int t;
}s[100005],f[100005];
int mp[100005];
bool operator<(node a,node b){ //从大到小排
return a.a1+a.b1<b.a1+b.b1;
}
int main() {
//freopen("1.txt", "r", stdin);
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d %d %d %d",&s[i].a1,&s[i].b1,&s[i].a2,&s[i].b2);
}
priority_queue<node> q;
ll suma,sumb;
suma=sumb=0;
for(int i=1;i<=n;i++){
if(s[i].a1<=s[i].b2 && s[i].b1<=s[i].a2)
continue;
if(s[i].a1+s[i].b1<=s[i].a2+s[i].b2){
if(s[i].b1>s[i].a2)
suma+=s[i].a2,sumb+=s[i].b1;
else if(s[i].a1>s[i].b2)
suma+=s[i].a1,sumb+=s[i].b2;
}
else{
node cnt;
cnt.a1=s[i].a1, cnt.b1=s[i].b1, cnt.a2=s[i].a2, cnt.b2=s[i].b2;
cnt.t=1;
q.push(cnt);
}
}
int cnt=0;
while(!q.empty()){
cnt++;
node tmp=q.top();
q.pop();
if(cnt%2){
suma+=tmp.a1;
}
else
sumb+=tmp.b1;
if(tmp.t==1){
tmp.t=2;
tmp.a1=tmp.a2;
tmp.b1=tmp.b2;
tmp.a2=0;
tmp.b2=0;
q.push(tmp);
}
}
printf("%I64d\n",(ll)(suma-sumb) );
return 0;
}
http://codeforces.com/gym/100820
先来想想问题:
题目只给定 n,r,w,h 也就是说要自己去决定 v 和 x
分析:
h=1e9
所以排除dp了?? 但n 1e5
所以我们可以将所有点 最多分成 1e5层
且每一层我们都最多只能经过一个点(或者不经过)
矩形
—————— l
|
| h
两点之间能够到达: vy=v;
t=h/v; vx=l/t=l*v/h
vx>=l*v/h v/r>=l*v/h => l*r<=h => r<=h/l; 所以能够到达和v 一毛钱关系都没有,至于h,l,r 有关。
然而图论写到一半发现: 第i层的点不会只和i+1层的点建边,哇,和后面的所有的点都可能建边,心态有点崩
还是看题解了,唉:对于这种边数太多的处理方法:
从上面的推理我们可以知道当车子位于某个点的时候,在y轴上前进 h ,那么在x轴能在[-h/r,h/r]移动
由此可以做两条射线与赛道相交得到 a,b; 且无论在哪个位置,这两条射线的夹角永远不会变
所以下一个能到达的点 必须满足 对其做同样的射线 有交点A,B 必须满足 A>=a && B>=b
如图:A可以到达B、C ,但无法到达D 。
那么对a做排序,然后对b做LIS 最长不下降子序列。
这里注意下,因为 B可以=b,所以不一定递增
呵呵,说出来好像又尽然如此简单,真的菜!!!真的瓜皮
顺便说下,最长不下降子序列。用upper_bound 很方便解决,可见代码。
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<string.h>
using namespace std;
#define ll __int64
/*
*/
ll n,r,w,h;
struct node{
ll x,y;
ll a,b;
bool operator < ( const node x) {
return a<x.a;
}
}f[100005];
ll lis[100005];
int main() {
freopen("1.txt", "r", stdin);
scanf("%I64d %I64d %I64d %I64d",&n,&r,&w,&h);
for(int i=1;i<=n;i++){
scanf("%I64d %I64d",&f[i].x,&f[i].y);
ll l1=f[i].x;
ll l2=w-f[i].x;
f[i].a=l1*r+f[i].y; //注意爆int啊
f[i].b=l2*r+f[i].y;
}
sort(f+1,f+n+1);
lis[1]=f[1].b;
int len=0;
for(int i=1;i<=n;i++){
int pos=upper_bound(lis+1,lis+len+1,f[i].b)-lis; //upper很好的解决的不下降问题
if(pos>len)
lis[++len]=f[i].b;
else
lis[pos]=f[i].b;
}
printf("%d\n",len);
return 0;
}