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

20191006

时间:2019-10-07 21:39:48      阅读:129      评论:0      收藏:0      [点我收藏+]

标签:mes   排序   res   ase   合并   back   ons   枚举   second   

A.

二分图+乱搞的做法被叉掉了。
先求出最多能赢多少次,然后枚举 \(a_i\) ,二分答案能与之匹配的 \(b_j\) ,check函数判断 \(a_i\)\(b_j\) 匹配时答案是否会变小。二分完之后把对应的 \(b_j\) 删掉。

Code

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
const int maxn=1003;
int n,tot,p[maxn],ANS[maxn];
bool del[maxn];
vector<P> a;
vector<int> b;
bool check(int res,int x){
    int tmp=b[x];
    b.erase(b.begin()+x);
    for(int i=-1,j=-1;;){
        for(i++;i<int(a.size())&&del[i];i++);
        if(i==int(a.size()))break;
        for(j++;j<int(b.size())&&b[j]<=a[i].first;j++);
        if(j==int(b.size()))break;
        res++;
    }
    b.insert(b.begin()+x,tmp);
    return res==tot;
}
int main(){
    scanf("%d",&n);
    a.resize(n),b.resize(n);
    for(int i=0;i<n;i++)scanf("%d",&a[i].first),a[i].second=i;
    for(int i=0;i<n;i++)scanf("%d",&b[i]);
    sort(a.begin(),a.end());
    sort(b.begin(),b.end());
    for(int i=0;i<n;i++)p[a[i].second]=i;
    for(int i=0,j=-1;i<n;i++){
        for(j++;j<n&&b[j]<=a[i].first;j++);
        if(j==n)break;
        tot++;
    }
    for(int i=0;i<n;i++){
        int x=a[p[i]].first,q=upper_bound(b.begin(),b.end(),x)-b.begin();
        del[p[i]]=1;
        int l=0,r=q-1,mid,ans1=-1,ans2=-1;
        while(l<=r){
            mid=(l+r)>>1;
            if(check(0,mid))ans1=mid,l=mid+1;
            else r=mid-1;
        }
        l=q,r=int(b.size())-1;
        while(l<=r){
            mid=(l+r)>>1;
            if(check(1,mid))ans2=mid,l=mid+1;
            else r=mid-1;
        }
        if(ans2==-1)ans2=ans1;
        else tot--;
        ANS[i]=b[ans2];
        b.erase(b.begin()+ans2);
    }
    for(int i=0;i<n;i++)printf("%d ",ANS[i]);
    return 0;
}

B.

考虑二分答案(角度)。

解 1

对于一个角度 \(\theta\) ,画一条与x轴夹角为 \(\theta\) 的直线,保证其在所有点的下方,然后将所有点按到该直线的距离从小到大排序,距离相同的按y坐标从大到小排序。然后把y坐标离散,用树状数组计算每个点的贡献。如果贡献之和 \(\geq\) 中位数,左移右端点。
卡精度。

解 2

考虑
\(\frac{y_j-y_i}{x_j-x_i}>k(x_i<x_j)\)
\(y_j-y_i>kx_j-kx_i\)
\(y_j-kx_j>y_i-kx_i\)

对于每个点 \((x_i,y_i)\) 算出 \(y_i-kx_i\) 然后二维数点。

Code 1

#include<bits/stdc++.h>
using namespace std;
typedef long long D;
const int maxn=50003;
const double pi=acos(-1),eps=1e-12;
int sgn(double x){return x<-eps?-1:x>eps;}
struct point{
    D x,y;
    point(){}
    point(D _x,D _y):x(_x),y(_y){}
}a[maxn];
int n,cntmp,t[maxn];
D mp[maxn];
double cot_mid;
void add(int pos,int k){while(pos)t[pos]+=k,pos-=pos&-pos;}
int query(int pos){int ret=0;while(pos<=cntmp)ret+=t[pos],pos+=pos&-pos;return ret;}
bool cmp(const point &p,const point &q){
    int tmp=sgn(p.x-mp[p.y]*cot_mid-(q.x-mp[q.y]*cot_mid));
    return tmp?tmp>0:q.y>p.y;
}
D f(double x){
    cot_mid=cos(x)/sin(x);
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=cntmp;i++)t[i]=0;
    D ret=0;
    for(int i=1;i<=n;i++){
        int tmp=query(a[i].y);
        ret+=tmp;
        add(a[i].y,1);
    }
    return ret;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i].x,&a[i].y),mp[++cntmp]=a[i].y;
    sort(mp+1,mp+cntmp+1);
    cntmp=unique(mp+1,mp+cntmp+1)-mp-1;
    for(int i=1;i<=n;i++)a[i].y=lower_bound(mp+1,mp+cntmp+1,a[i].y)-mp;
    D N=1ll*n*(n-1)/2,rnk1=(N+1)/2,rnk2=N/2+1;
    double l=0,r=pi,mid,ans1=-1,ans2=-1;
    while(sgn(r-l)>0){
        mid=(l+r)/2;
        if(f(mid)>=rnk1)ans1=mid,r=mid-eps;
        else l=mid+eps;
    }
    l=0,r=pi;
    while(sgn(r-l)>0){
        mid=(l+r)/2;
        if(f(mid)>=rnk2)ans2=mid,r=mid-eps;
        else l=mid+eps;
    }
    printf("%.10lf\n",N&1?ans1:(ans1+ans2)/2);
    return 0;
}

C.

考虑对于一个点 \(u\) ,在完整图中所有与 \(u\) 相邻的、编号比 \(u\) 大的节点的颜色都不能相同,因为都有边。所以 \(u\)\(n-(\text{所有与}u\text{相邻的、编号比}u\text{大的节点个数})\) 种取值。
如何维护完整图中所有与 \(u\) 相邻的、编号比 \(u\) 大的节点?线段树合并或set启发式合并。

Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=100003,mod=998244353;
int mul(long long x,int y){return x*y%mod;}
vector<int> g[maxn];
int n,m,f[maxn];
set<int> st[maxn];
int find(int x){return x!=f[x]?f[x]=find(f[x]):f[x];}
void merge(int x,int y){
    int fx=find(x),fy=find(y);
    if(fx!=fy){
        if(st[fx].size()<st[fy].size())swap(fx,fy);
        while(!st[fy].empty())st[fx].insert(*st[fy].begin()),st[fy].erase(st[fy].begin());
        f[fy]=fx;
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)f[i]=i;
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        if(u>v)swap(u,v);
        g[u].push_back(v),g[v].push_back(u);
        st[u].insert(v);
    }
    int ans=1;
    for(int u=1;u<=n;u++){
        for(int v:g[u])if(v<u)merge(u,v);
        int fu=find(u);
        if(st[fu].count(u))st[fu].erase(u);
        ans=mul(ans,n-st[fu].size());
    }
    printf("%d\n",ans);
    return 0;
}

20191006

标签:mes   排序   res   ase   合并   back   ons   枚举   second   

原文地址:https://www.cnblogs.com/BlogOfchc1234567890/p/11632181.html

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