Wannafly每日一题 2.17

来源:互联网 发布:要开淘宝网店怎么弄 编辑:程序博客网 时间:2024/05/17 01:11

首先说明: 题解都是从 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,  双方都想要选择后手,且 如果先手都没有收益,那不会选2a1+b1<=a2+b2, 即对于该对照片,双方的后手收益都好于先手收益,且必有a1>b2或b1>a2,即必有一方有正收益 ,如果不选则没收益,但先选仍有收益3 对于剩下的物体  排除了废物品 和 后手有利物品那么只剩下 先手有利的物品了?? 如果不仅让自己得分最多,且让对手最少一开始想的是a1-b2+a2-b1 = a1+a2 -(b1+b2) 。。。然后越想越复杂然而看了题解,似乎我们只需要注意a1+b1 ,按这个来作为条件,这样子就完成了上面的要求。真是神奇!还有个问题:对于一对牌:a1 b1a2 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
B

先来想想问题:
题目只给定 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;}
0 0
原创粉丝点击