19CSP-S十一高端峰会—青岛站 题解
Posted tyouchie
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了19CSP-S十一高端峰会—青岛站 题解相关的知识,希望对你有一定的参考价值。
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 ",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 ",ans); } return 0; }
T3
不会写 数位DP 水了30 咕咕咕了
以上是关于19CSP-S十一高端峰会—青岛站 题解的主要内容,如果未能解决你的问题,请参考以下文章