问题描述
云顶之弈是一款最近很流行的自走棋游戏,玩家需要抽取卡片提升装备并通过巧妙的布局赢得游戏.
赢得游戏的关键在于良好的策略,但运气也是必不可少的.
游戏公司当然不会放过一个捞金的好机会,于是,如果抽不到想要的卡片,可以在商店购买.
当然,游戏公司也会利用人们的侥幸心理,让他们花钱购买抽卡的机会.商店进行保证,连抽c次一定可以获得想要的卡片.
具体来说,每个光顾商店的人有一个氪金值 和一个欧气值 ,若他的欧气值大于等于c,他会选择连抽c次获得卡片,若他的欧气值小于c,且他的氪金值大于等于卡片的价格p,他会氪金买他想要的卡片.否则他会离开商店.
现在,游戏公司要做的就是定下需要连抽多少次才能保证获得想要的卡片,即一个人连抽c次游戏公司可以赚取$c*w$的利润.游戏公司想要你帮他计算c 定为1到$1+max(b_i)$的最大利润.(p不确定).
输入格式
第一行两个数,n,w,表示光顾商店的人和单次抽取卡片的费用.
接下来n行,每行两个数,表示第i 个人的氪金值 $a_i$和欧气值$b_i$ .
输出格式
一行,共$1+max(b_i)$个数,第i个数表示c=i时的最大利润.
输入样例1
2 1
2 0
0 2
输出样例1
3 4 2
输入样例2
3 1
3 1
2 2
1 3
输出样例2
3 7 7 4
数据范围
$n\leq10^5$,$a_i,b_i\leq10^5$
基本思路思路很好想,枚举c求答案,加上离散化,时间复杂度$O(nmax(a_i))$
可以发现求答案的主要过程抽象为这样一种数据结构,支持给1~x中每个数加上它本身,询问1~n中的最大值
然后自然而然想到要用分块
如果修改的是一个完整块,怎样维护其中的最大值?
我们知道,每个位置对应的值为$i*tag_i+s_i$
修改时,只有$tag_i$会变化,而且单调递增
另外,在每个块内$i$也是单调递增的
是不是有一点点像斜率优化?
把每个元素看作$(i,s_i)$,维护一个下凸包,满足对于$i<j<k$,$\frac{s_i-s_j}{i-j}<\frac{s_j-s_k}{j-k}$
每次修改时,删去$s_i-s_j\leq(j-i)*tag_{block_i}$的
剩下的暴力重建即可,时间复杂度$O(n\sqrt{n})$
很巧妙地在分块中结合了斜率优化的思想
#include<bits/stdc++.h> using namespace std; const int N=1e5+5; int n,m,n_n,w,mxb,mxa; int block[N],lft[N],rgt[N]; long long tag[N],s[N],maxx[N]; struct person {int a,b;} p[N]; bool cmp(person u,person v) {return u.b<v.b;} int q[505][505],h[505],t[505]; void update(int r) { int R=block[r]; for(int i=1;i<R;++i) { ++tag[i]; while(h[i]<t[i] && s[q[i][h[i]]]-s[q[i][h[i]+1]]<= 1ll*(q[i][h[i]+1]-q[i][h[i]])*tag[i]) ++h[i]; maxx[i]=1ll*q[i][h[i]]*tag[i]+s[q[i][h[i]]]; } for(int i=lft[R];i<=r;++i) s[i]+=i; for(int i=lft[R];i<=rgt[R];++i) s[i]+=tag[R]*i; h[R]=1,t[R]=tag[R]=0; for(int i=lft[R];i<=rgt[R];++i) { while(t[R]>h[R] && 1ll*(s[q[R][t[R]]]-s[i])*(q[R][t[R]-1]-q[R][t[R]])>= 1ll*(q[R][t[R]]-i)*(s[q[R][t[R]-1]]-s[q[R][t[R]]])) --t[R]; q[R][++t[R]]=i; } while(h[R]<t[R] && s[q[R][h[R]]]<=s[q[R][h[R]+1]]) ++h[R]; maxx[R]=s[q[R][h[R]]]; } long long ask_max() { long long ret=0; for(int i=1;i<=n_n;++i) ret=max(ret,maxx[i]); return ret; } int main() { freopen("could.in","r",stdin); freopen("could.out","w",stdout); scanf("%d%d",&n,&w); for(int i=1;i<=n;++i) { scanf("%d%d",&p[i].a,&p[i].b); mxa=max(p[i].a,mxa); } sort(p+1,p+n+1,cmp); mxb=p[n].b+1; m=sqrt(mxa), n_n=(mxa-1)/m+1; for(int i=1;i<=mxa;++i) block[i]=(i-1)/m+1; for(int i=1;i<=n_n;++i) { lft[i]=(i-1)*m+1, rgt[i]=min(i*m,mxa); h[i]=1, t[i]=1, q[i][1]=rgt[i]; } int pl=1,pr=1; for(int i=1;i<=mxb;++i) { long long ans=0; while(p[pr].b<i && pr<=n) ++pr; ans=1ll*i*w*(n-pr+1); for(int j=pl;j<pr;++j) update(p[j].a); pl=pr; printf("%lld ",ans+ask_max()); } return 0; }
原文地址:https://www.cnblogs.com/w19567/p/11272705.html