[CF505E]Mr. Kitayuta vs. Bamboos/[海军国际项目办公室]迷途竹林
Mr. Kitayuta vs. Bamboos
迷途竹林事实上就是经 
       
        
         
          
           
           
             T 
            
           
             i 
            
           
             w 
            
           
             A 
            
           
             i 
            
           
             r 
            
           
             O 
            
           
             A 
            
           
             O 
            
           
          
         
        
          \color{red}{TiwAirOAO} 
         
        
      TiwAirOAO巨佬扩大数据范围强化后的版本。真的是强化了吗
 不过做了两遍都不会做的我还是埋了吧
题解
很明显,由于我们每次砍树是让树高从 
     
      
       
       
         h 
        
       
      
        h 
       
      
    h变成 
     
      
       
       
         max 
        
       
          
        
       
         ( 
        
       
         0 
        
       
         , 
        
       
         h 
        
       
         − 
        
       
         p 
        
       
         ) 
        
       
      
        \max(0,h-p) 
       
      
    max(0,h−p),每次减少的树高不是固定的,这就很难做了,况且它的树高还是会根据时间增加的。
 既然我们已经无法简单地知道我们当前删哪个是最优的,不如考虑倒着来。
 很显然,我们可以先二分我们的答案,也就是最后的最高的树高度是多少,看如果是这个高度的话能否达到我们的初始状态。
 转化回到初始状态,我们的操作相当于也跟原来倒着来的。
 我们可以先将所有树的最终高度都设为 
     
      
       
       
         m 
        
       
         i 
        
       
         d 
        
       
      
        mid 
       
      
    mid,我们每次生长相当于所有树的高度减少 
     
      
       
        
        
          a 
         
        
          i 
         
        
       
      
        a_{i} 
       
      
    ai,而每次砍树相当于让我们树的高度加上 
     
      
       
       
         p 
        
       
      
        p 
       
      
    p。
 很明显,我们树的高度不可能为负数,所以当我们需要时刻保证我们的树高时时刻刻 
     
      
       
       
         ⩾ 
        
       
         0 
        
       
      
        \geqslant 0 
       
      
    ⩾0。
 而我们最后的树高也是必须 
     
      
       
       
         ⩾ 
        
        
        
          h 
         
        
          i 
         
        
       
      
        \geqslant h_{i} 
       
      
    ⩾hi的,否则我们的答案树高一定更高。
 很明显,我们倒退回去的方式肯定可以转化成一种正着砍过来的方式,而如果我们的最终高度 
     
      
       
       
         ⩾ 
        
        
        
          h 
         
        
          i 
         
        
       
      
        \geqslant h_{i} 
       
      
    ⩾hi,那么我们最终高度为 
     
      
       
        
        
          h 
         
        
          i 
         
        
       
      
        h_{i} 
       
      
    hi时一定也是有解的。
 由于我们过程中需要满足 
     
      
       
        
        
          h 
         
        
          i 
         
        
       
         ⩾ 
        
       
         0 
        
       
      
        h_{i}\geqslant 0 
       
      
    hi⩾0的要求,所以我们可以每次选择一个会最快变得小于 
     
      
       
       
         0 
        
       
      
        0 
       
      
    0的点,将它的高度加上 
     
      
       
       
         p 
        
       
      
        p 
       
      
    p。最终 
     
      
       
       
         ⩾ 
        
        
        
          h 
         
        
          i 
         
        
       
      
        \geqslant h_{i} 
       
      
    ⩾hi的要求,我们可以在最后时刻,将所有还没有用出的操作全部用出,看能否达到条件。
 上面的过程我们可以通过优先队列来维护,但优先队列是 
     
      
       
       
         log 
        
       
          
        
       
      
        \log 
       
      
    log的,事实上我们完全可以直接记录下来在每个时刻,有哪些位置即将不合法,将之后的操作加上去,再将它放到下一个可能不合法的位置就行了。
时间复杂度很明显的 O ( ( n + m k ) l o g A ) O\left((n+mk)log\,A\right) O((n+mk)logA)。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;       
const LL INF=0x3f3f3f3f;       
const int mo=1e9+7;
const int inv2=499122177;
const int jzm=2333;
const int lim=1e9;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,m,k,cnt[MAXN];LL p;
struct ming{LL h,a;}s[MAXN];
vector<int>vec[MAXN];
bool check(LL mid){
	//printf("check %lld\n",mid);;
	for(int i=1;i<m;i++)vec[i].clear();int summ=0;
	for(int i=1;i<=n;i++){cnt[i]=0;LL tmp=mid/s[i].a;if(tmp<m)vec[tmp].pb(i);}
	for(int i=1;i<m;i++){
		summ+=k;//printf("arrive %d\n",i);
		for(int j=0;j<(int)vec[i].size();j++){
			int u=vec[i][j];cnt[u]++;summ--;
			if(summ<0||!s[u].a)return 0;
			LL tmp=(mid+1ll*cnt[u]*p)/s[u].a;
			if(tmp<m)vec[tmp].pb(u);
		}
	}
	summ+=k;
	for(int i=1;i<=n;i++)
		while(mid+1ll*cnt[i]*p-1ll*m*s[i].a<s[i].h&&summ>=0)
			cnt[i]++,summ--;
	return summ>=0;
}
signed main(){ 
	read(n);read(m);read(k);read(p);LL maxx=0;
	for(int i=1;i<=n;i++)read(s[i].h),read(s[i].a),maxx=max(maxx,s[i].a);
	LL l=maxx,r=1e15;while(l<r){LL mid=l+r>>1LL;if(check(mid))r=mid;else l=mid+1LL;}
	printf("%lld\n",l);
	return 0;
}
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号