NKOJ 7614
题目
思路:
考虑只有一个讲题区间的做法,直接预处理每一个点被覆盖的次数就可以了。
但当遇到另一个区间时,我们想要快速确定一个人如何选择讲师
因为一个线段取的是交集最大的讲师线段,所以我们考虑线段交集随讲师线段移动的关系,肯定是先变大,然后不变,在变小
而且有一个很重要的性质:函数有对称性
所以只要离函数中点越近,就越优。
当与函数中点重叠的时候,就是线段中点重合
所以每个线段会取离它中点最近的讲师线段的中点。
而画一下图就可以发现这样的话一定存在一个分界点,分界点左侧全部取讲师1,右侧全部取讲师2
此时预处理前后缀单线段最优答案,枚举分界点相加即可
难点:
难想到快速确定一个人如何选择讲师这一个方向
线段中点trick
#include<bits/stdc++.h>
using namespace std;
struct FIO{static const int BUF_SIZE=1<<19;char _i[BUF_SIZE],*_1=_i,*_2=_i,_o[BUF_SIZE],*_t=_o;inline char _gt(){if(_1==_2){_1=_i;_2=_i+fread(_i,1,BUF_SIZE,stdin);}return _1==_2?EOF:*_1++;}inline void _pt(char c){if(_t-_o==BUF_SIZE){fwrite(_o,1,BUF_SIZE,stdout);_t=_o;}*_t++=c;}int _pr=6,le,_ob[20];template<typename T>FIO&operator>>(T&x){x=0;char c=_gt();bool sg=false;while(c!=EOF&&(c<'0'||c>'9')){if(c=='-')sg=true;c=_gt();}while(c!=EOF&&c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=_gt();}if(sg)x=-x;return*this;}FIO&operator>>(char*s){char c=_gt();while(c!=EOF&&c<33)c=_gt();while(c!=EOF&&c>=33)*s++=c,c=_gt();*s='\0';return*this;}FIO&operator>>(string&s){s.clear();char c=_gt();while(c!=EOF&&c<33)c=_gt();while(c!=EOF&&c>=33)s+=c,c=_gt();return*this;}FIO&operator>>(char&x){char c=_gt();while(c!=EOF&&c<33)c=_gt();x=c;return*this;}FIO&operator>>(double&x){x=0;char c=_gt();bool sg=0;while(c!=EOF&&c<33)c=_gt();if(c=='-'){sg=1;c=_gt();}while(c!=EOF&&c>='0'&&c<='9'){x=x*10+(c^48);c=_gt();}if(c=='.'){c=_gt();double tp=0.1;while(c!=EOF&&c>='0'&&c<='9'){x+=(c^48)*tp;tp*=0.1;c=_gt();}}if(sg)x=-x;return*this;}FIO&setprecision(int n){_pr=n<0?0:n;return*this;}template<typename T>FIO&operator<<(T x){if(x<0){_pt('-');x=-x;}if(x==0){_pt('0');return*this;}char _b[20];int ps=0;while(x>0){_b[ps++]=(x%10)^48;x/=10;}while(ps>0)_pt(_b[--ps]);return*this;}FIO&operator<<(const char*s){while(*s)_pt(*s++);return*this;}FIO&operator<<(const string&s){for(char c:s)_pt(c);return*this;}FIO&operator<<(char c){_pt(c);return*this;}FIO&operator<<(double x){if(x<0)_pt('-'),x=-x;if(isnan(x))return _pt('n'),_pt('a'),_pt('n'),*this;if(isinf(x))return _pt('i'),_pt('n'),_pt('f'),*this;long long ip=(long long)x;x-=ip;if(_pr==0){x*=10;if(x>=5)ip++;return*this<<ip;}le=0;_ob[0]=0;for(int i=1;i<=_pr;i++){x*=10;_ob[++le]=(int)x;x-=(int)x;}x*=10;int _tp=(int)x;if(_tp>=5){int j=le;_ob[le]++;while(_ob[j]==10)_ob[j-1]++,_ob[j]=0,j--;}ip+=_ob[0];*this<<ip<<".";for(int i=1;i<=le;i++)*this<<_ob[i];return*this;}~FIO(){fwrite(_o,1,_t-_o,stdout);}}fst;
#define cin fst
#define cout fst
#define il inline
#define N 2005
int n,m,k;
struct seg{
int l,r;
}a[N];
int s[N],pre[N],suf[N];
int main(){
cin>>n>>m>>k;
for(int i=1;i<=m;i++){
cin>>a[i].l>>a[i].r;
}
sort(a+1,a+m+1,[](seg a,seg b){
return a.l+a.r<b.l+b.r;
});
for(int p=1;p<=m;p++){
fill(s+1,s+n+2,0);
for(int i=1;i<=p;i++){
s[a[i].l]++; s[a[i].r+1]--;
}
for(int i=1;i<=n;i++)s[i]+=s[i-1];
for(int i=1;i<=n;i++){
s[i]+=s[i-1];
pre[p]=max(pre[p],s[i]-s[max(i-k,0)]);
}
}
for(int p=m;p;p--){
fill(s+1,s+n+2,0);
for(int i=m;i>=p;i--){
s[a[i].r]++; s[a[i].l-1]--;
}
for(int i=n;i>=1;i--)s[i]+=s[i+1];
for(int i=n;i>=1;i--){
s[i]+=s[i+1];
suf[p]=max(suf[p],s[i]-s[min(i+k,n+1)]);
}
}
int ans=0;
for(int i=0;i<=m;i++){
ans=max(ans,pre[i]+suf[i+1]);
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号