题解P6163【[Cnoi2020]领域极限】
xuanxuan001 · · 题解
打 ARC 的时候做了这题,赛后知道洛谷上有这道原题,不得不说AT官方题解的做法是真的妙,所以就讲讲我赛时的贪心做法吧(???)。
先推个式子,首先把
先抛掉前面那个那个 2,然后考虑每个 x 被算了多少次,转化为
也就是说,第
最开始一定是让所有人尽量靠后,所以直到遇到某个人的右端点了再把他放下。
考虑将所有的
那么首先
然后接下来就是比较关键的一步了,就是如果
感觉整篇题解写的挺草率的,也不知道讲没讲明白,欢迎各位指正。
代码:
#include<cstdio>
#include<algorithm>
#define TY ll
#define MAXN 300002
#define debug if( 1 &&putchar('>'))
#define FOR(i,a,b) for(TY i=(a);i<=(b);++i)
#define fOR(i,a,b) for(TY i=(a);i<(b);++i)
#define ROF(i,a,b) for(TY i=(a);i>=(b);--i)
#define rOF(i,a,b) for(TY i=(a);i>(b);--i)
using namespace std;
typedef long long ll;
const TY M=998244353;
typedef unsigned long long ull;
TY _abs(TY a){return a<0?-a:a;}
TY maxn(TY a,TY b){return a>b?a:b;}
TY minn(TY a,TY b){return a<b?a:b;}
TY gcd(TY a,TY b){return b?gcd(b,a%b):a;}
TY qp(TY a,TY b){TY ans=1;do{if(b&1)ans=ans*a%M;a=a*a%M;}while(b>>=1);return ans;}
char getc(){char ch=getchar();while(ch==' '||ch=='\n')ch=getchar();return ch;}
TY qr(){
char ch=getchar();TY s=0,x=1;
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')x=-1;
for(;ch>='0'&&ch<='9';ch=getchar())s=s*10+ch-'0';return x*s;
}void qw(TY a,char ch){
if(a<0){a=-a;putchar('-');}
if(a>9)qw(a/10,0);putchar(a%10+'0');
if(ch)putchar(ch);
}TY n=qr(),m,l[MAXN],r[MAXN],b[MAXN<<1],ans,cnt,lst,vl[MAXN<<1],vr[MAXN<<1];
inline TY js(TY x,TY y){return (y-x)*(x+y-n);}
//将(lst,cnt]的人放在某个位置的权值和,其实循环计算也可以
int main(){
FOR(i,1,n){b[i*2-1]=l[i]=qr();b[i<<1]=r[i]=qr();}
sort(b+1,b+(n<<1|1));m=unique(b+1,b+(n<<1|1))-b-1;
FOR(i,1,n){
++vl[l[i]=lower_bound(b+1,b+m+1,l[i])-b];
++vr[r[i]=lower_bound(b+1,b+m+1,r[i])-b];//预处理一些数组
}FOR(i,1,m){
cnt+=vl[i];
if(lst+vr[i]+cnt>n){//如果开始转变为后半段
ans+=b[i]*js(lst,cnt);
FOR(j,i+1,m)fOR(k,0,vl[j])
ans+=((++cnt)*2-n-1)*b[j];//将后面的全部取左端点
break;//考虑完直接退出
}fOR(j,0,vr[i])ans+=((++lst)*2-n-1)*b[i];//更新lst
}qw(ans,0);
return 0;
}