[SCOI2015]国旗计划
[SCOI2015]国旗计划
https://ac.nowcoder.com/acm/problem/20302
非常考验技巧的一题...emm这个我最不会了...
首先断环为链,也就是把士兵和站台复制一份放在后面,这样只需要考虑覆盖一个区间而已
因为区间两两不包含,所以当选择了第个士兵后
现在覆盖了
那么从左端点不大于里选,一定是选右端点最大的最优秀了
那么这样选择的士兵就固定了...
关键就找下一个士兵的过程,可以二分预处理
但是倍增更快!!!
说起来 简单,但还是不会写,实现能力太差了...
#include <bits/stdc++.h> using namespace std; int n,m; const int maxn = 4e5+10; struct soldier { int id,l,r; }a[maxn]; bool com(soldier a,soldier b){ return a.l<b.l; } int flow[maxn],f[maxn][22]; void solve(int k) { int limit = a[k].l+m, ans = 1, index = k; for(int i=20;i>=0;i-- ) if( f[k][i]!=0&&a[f[k][i]].r<limit ) ans += (1<<i),k=f[k][i]; flow[a[index].id] = ans+1; } void init() { for(int i=1,index = i;i<=2*n;i++) { while( index<=2*n && a[index].l<=a[i].r ) index++;//其实这里可以二分更快 f[i][0] = index-1;//最靠近r的战士,说明他的r也最远 } for(int i=1;i<=20;i++) for(int j=1;j<=2*n;j++) f[j][i] = f[f[j][i-1]][i-1]; } int main() { cin >> n >> m; for(int i=1;i<=n;i++) { scanf("%d%d",&a[i].l,&a[i].r); if( a[i].r<a[i].l ) a[i].r+=m; a[i].id = i; } sort( a+1,a+1+n,com );//注意先排序再复制 for(int i=n+1;i<=2*n;i++) a[i]=a[i-n],a[i].l+=m,a[i].r+=m; init(); for(int i=1;i<=n;i++) solve(i); for(int i=1;i<=n;i++) printf("%d ",flow[i] ); }