码迷,mamicode.com
首页 > 其他好文 > 详细

19CSP-S十一高端峰会—青岛站 题解

时间:2019-10-06 16:30:08      阅读:91      评论:0      收藏:0      [点我收藏+]

标签:优化   题解   printf   方法   double   pen   fread   cpp   mic   

 T1

 

技术图片

写一下考场上的思路8 反正看到 我第一眼觉得是个解析几何 后来我竟然有个鬼畜的想法 我竟然想求出所有直线焦点的坐标

后来 我发现 这个做法非常的不科学 甚至就达到了n^2 的复杂度 但是 求出来坐标也没什么用 很自闭

后来我yy了几个很大的图 然后 模拟了一遍题目 发现画了很多很多的点的图 发现答案都是3 当时 我就思考 会不会没有4的情况

然后 大胆 猜结论 不存在4的情况 所以 我们 简单证明一下这个结论 没有4个点的完全图

其实有一种比较严谨的证明方法 :

考虑构造 每个点p 只会被两条直线 所以不会有4个点是相邻的 所以考虑 将x y排序 考虑到p时 使用相邻没使用过的颜色即可 

所以 存在3种颜色的时候 存在三个不同的 斜率即可 2种颜色的时候 大于2条直线并且 只存在2个斜率 1个 和 0个 应该不用说吧

#include<bits/stdc++.h>
#define eps 1e-10
#define INF 2000000010
#define inf 2000000100
using namespace std;
const int N=1000010;
int n,flag,mark,res1,T;
long double s1,s2;
char buf[1<<15],*fs,*ft;
inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
inline int read() {
    int x=0,f=1;char ch=getc();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getc();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getc();}
    return x*f;
}
struct gg {
    long double s;
}t[N];
typedef long double ld;
inline bool check(long double a,long double b) {
    if(fabs(a-b)<=eps) return 1;
    return 0;
}
//可以证明的是 不存在 >4 的情况 因为不存在 4个点的 完全图
//3的情况 是 存在三角形  
//2的情况 类似 网格图 
int main() {
    //freopen("1.in.cpp","r",stdin);
    T=read();
    while(T--) {
        n=read();
        flag=res1=mark=0;s1=inf;s2=inf;
        for(int i=1;i<=n;++i) {
            long double x,y,xx,yy;
            x=read(); y=read();
            xx=read(); yy=read();
            if(y<yy) {
                swap(x,xx);
                swap(y,yy);
            }
            if(x==xx) {
                t[i].s=INF;
                continue;
            }
            t[i].s=(y-yy)/(x-xx);
        }
        for(int i=1;i<=n;++i) {
            if(check(s1,inf)) {
                s1=t[i].s;
                continue;
            }
            if(check(s1,t[i].s)) { 
                mark=1;
                continue;
            }
            if(check(s2,inf)) {
                s2=t[i].s;
                res1=1;
                continue;
            }
            if(check(s2,t[i].s)) {
                mark=1;
                continue;
            }
            flag=1;
        }
        if(flag) {
            puts("3");
            continue;
        }
        if(res1&&mark) {
             puts("2");
            continue;
        }
        if(res1) {
            puts("1");
            continue;
        }
        puts("0");
        continue;
    }
    return 0;
}

 T2 

反正是个贪心吧 反正考场上只会写贪心 假设i在j之前的贡献 和j在i之前的贡献 分别写出来 然后 考虑 什么情况下

i在j之前贡献较大的前提下就是 ti*pj<pi*tj 然后排序 写了个nmlogn的复杂度 水了70 

但是 考虑怎么优化 有个比较巧妙的思路

考虑将m离线 那么就是每次在元素中 插入一个位置 然后删除原来的位置 然后考虑这个时候 对答案带来的贡献

首先对于他自己位置的贡献 只和它前面位置T之和有关 然后对后面的贡献 只和后面的P之和有关

然后考虑一种数据结构 支持查询 区间和就行了

然后考虑将所有n+m中都排序 这个时候就空出来了n+m个位置 然后将前n个插进去 然后考虑 这m个 每次更改删除 插入即可

因为此时有空位置 所以不用 考虑整个序列的移动了 思想很巧妙

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &x) {
    x=0;T f=1,ch=getchar();
    while(!isdigit(ch))     {if(ch==-) f=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x*=f;
} 
const int N=200010;
const int M=100010; 
ll n,m,T,x,pi,ti;
struct gg {
    ll p,t,id;
}a[M],t[M],s[N]; 
int c[N],q[N];//两个BIT c:t q:p 
int pos[N];
inline ll lowbit(ll x) {return x&(-x);}
inline void add(ll x,ll d) {
    for(;x<=n+m;x+=lowbit(x)) {
        c[x]+=d;
    }
}
inline void add1(ll x,ll d) {
    for(;x<=n+m;x+=lowbit(x)) {
        q[x]+=d;
    }
}
inline ll query(ll x) {//查询t 
    ll res=0;
    for(;x;x-=lowbit(x)) {
        res+=c[x];     
    } 
    return res;
} 
inline ll query1(ll x) {//查询p 
    ll res=0;
    for(;x;x-=lowbit(x)) {
        res+=q[x];
    }
    return res;
}
inline bool mycmp(gg x,gg y) {
    return x.t*y.p<y.t*x.p;
}
int main() {
    //freopen("1.in.cpp","r,",stdin);
    read(n); read(m); read(T);
    for(int i=1;i<=n;i++) {
        read(a[i].p); read(a[i].t);
        a[i].id=i; s[i]=a[i];
    }
    for(int i=1;i<=m;i++) {
        read(x); read(pi); read(ti);
        gg k=(gg){pi,ti,i+n};
        s[i+n]=k;
        k.id=x;
        t[i]=k;
    }
    sort(s+1,s+n+m+1,mycmp);
    for(int i=1;i<=n+m;i++) pos[s[i].id]=i;//cout<<pos[s[i].id]<<" "<<s[i].id<<endl;
    for(int i=1;i<=n;i++) {
        add(pos[i],a[i].t); add1(pos[i],a[i].p);
    }
    ll ans=0;
    for(int i=1;i<=n;i++) {
        ans+=1ll*a[i].p*(T-query(pos[i]));
    }
    printf("%lld\n",ans);
    for(int i=1;i<=m;i++) {
        ans-=1ll*a[t[i].id].p*(T-query(pos[t[i].id]));//减去之前的贡献 
        add(pos[t[i].id],-a[t[i].id].t);
        add1(pos[t[i].id],-a[t[i].id].p);
        ans+=1ll*(query1(n+m)-query1(pos[t[i].id]))*a[t[i].id].t;
        ans-=1ll*(query1(n+m)-query1(pos[i+n]))*t[i].t;
        add(pos[i+n],t[i].t);
        add1(pos[i+n],t[i].p);
        ans+=1ll*(T-query(pos[i+n]))*t[i].p;
        a[t[i].id]=t[i];
        printf("%lld\n",ans);
    }
    return 0;
} 

 T3

不会写 数位DP 水了30 咕咕咕了

 

 

19CSP-S十一高端峰会—青岛站 题解

标签:优化   题解   printf   方法   double   pen   fread   cpp   mic   

原文地址:https://www.cnblogs.com/Tyouchie/p/11625671.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!