标签:mes 排序 res ase 合并 back ons 枚举 second
二分图+乱搞的做法被叉掉了。
先求出最多能赢多少次,然后枚举 \(a_i\) ,二分答案能与之匹配的 \(b_j\) ,check函数判断 \(a_i\) 与 \(b_j\) 匹配时答案是否会变小。二分完之后把对应的 \(b_j\) 删掉。
#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;
}
考虑二分答案(角度)。
对于一个角度 \(\theta\) ,画一条与x轴夹角为 \(\theta\) 的直线,保证其在所有点的下方,然后将所有点按到该直线的距离从小到大排序,距离相同的按y坐标从大到小排序。然后把y坐标离散,用树状数组计算每个点的贡献。如果贡献之和 \(\geq\) 中位数,左移右端点。
卡精度。
考虑
\(\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\) 然后二维数点。
#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;
}
考虑对于一个点 \(u\) ,在完整图中所有与 \(u\) 相邻的、编号比 \(u\) 大的节点的颜色都不能相同,因为都有边。所以 \(u\) 有 \(n-(\text{所有与}u\text{相邻的、编号比}u\text{大的节点个数})\) 种取值。
如何维护完整图中所有与 \(u\) 相邻的、编号比 \(u\) 大的节点?线段树合并或set启发式合并。
#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;
}
标签:mes 排序 res ase 合并 back ons 枚举 second
原文地址:https://www.cnblogs.com/BlogOfchc1234567890/p/11632181.html