洛谷P4155.国旗计划
-
贪心 + 倍增
- 对于每一个i来说,要找最优解需要尽可能选择最远的战士
- 枚举的复杂度是无法接受的,因此可以采用倍增优化
- 令f[i,j]为第i个战士往右(断环成链) 选择2j个战士(不一定是距离2j)到达的战士编号
- f[i,j] = f[f[i,j-1][j-1];
- 在搜索时采用先大跳后小跳的策略(同LCA),此时ans += 2i
-
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int N= 2e5+5; int n,m; int ans[N]; struct node{ int id,l,r; }s[N*2]; int cmp(node a,node b) { return a.l < b.l; } int f[N*2][20]; void pre() { //对于每一个i,找到尽可能远的第一个战士编号 for(int i=1,p=i;i<=2*n;i++) { while(p <= 2*n && s[p].l <= s[i].r) p++; f[i][0] = p - 1; } //f的递推表达式 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]; } void solve(int k) { //定上限l + m,res初始化为1(自身), int lim = s[k].l + m,res = 1,p = k; //从大到小遍历 for(int i=19;i>=0;i--) { //如果能跳,并且lim不取等(最后差一点不跳了,存入res + 1) if(f[k][i] != 0 && s[f[k][i]].r < lim) { res += (1 << i); k = f[k][i]; } } ans[s[p].id] = res + 1; } int main() { cin>>n>>m; for(int i=1;i<=n;i++) { cin>>s[i].l>>s[i].r; if(s[i].r < s[i].l) s[i].r += m; s[i].id = i; } sort(s+1,s+n+1,cmp); //断环成链 for(int i=1;i<=n;i++) { s[i+n] = s[i]; s[i+n].l = s[i].l + m; s[i+n].r = s[i].r + m; } pre(); for(int i=1;i<=n;i++) solve(i); for(int i=1;i<=n;i++) cout<<ans[i]<<" "; }