2024ICPC武汉邀请赛-G.Pack-数论分块、整除运算相关的不等式

link:https://codeforces.com/gym/105143
Group contests:https://codeforces.com/group/DWEH34LQgT/contest/521901
题意:有 \(n\)\(A\) 物品, \(m\)\(B\) 物品,两种物品价值分别是 \(a,b\),若干件 \(A\) 和若干件 \(B\) 可以打包成一个商品,打包尽可能多的商品的情况下让剩余的 \(A,B\) 物品件数和最小,同时商品价值恰好是 \(k\)


虽然感觉是比较基础的题…但是写的时候并不是那么熟练,一些细节的地方处理了一小会儿,感觉还是有必要进行一个复盘。

题意翻译过来就是求 $$n+m-\min(\lfloor\frac{n}{x}\rfloor,\lfloor\frac{m}{y}\rfloor)\times(x+y)$$
的最小值,\(n+m\) 固定,也就是最大化后面的部分

注意到 \(n,m\) 对称,而且 \(\lfloor n/x\rfloor\) 只有 \(\Theta(\sqrt n)\) 种取值,强制让某个数的块小(例如 \(x\) ),就变成了如下问题:

  • 找到每个 \(\lfloor n/x\rfloor=v\) 的块,强制让 \(v=\lfloor n/x\rfloor \leq \lfloor m/y\rfloor\)
  • 对每个块 \(v\),可以确定 \(x\) 的一个取值范围。
  • 对不定方程 \(ax+by=k\) ,先求得一组 \(ax_0+by_0=\gcd(a,b)\equiv d\) 的特解,将特解乘上 \(k/d\) 得到右侧是 \(k\) 的特解,写出其通解为

\[\begin{aligned}x&=x_0+t\cdot \frac{b}{d}\\ y&=y_0-t\cdot \frac{a}{d}\end{aligned}\]

  • 要求满足不等式:
    • 1、\(x\geq 0\)\(\lfloor n/x\rfloor=v\).
    • 2、\(y\geq 0\)
    • 3、\(v \leq \lfloor m/y\rfloor\).
  • 分别求解:
    • 1、除法分块得到一个 \(x\) 的范围 \([L,R]\),所以\(L\leq x_0+tb/d\leq R\),$$\lceil(L-x_0)\frac{d}{b} \rceil \leq t\leq \lfloor (R-x_0)\frac{d}{b}\rfloor$$
    • 2、\(y=y_0-t\cdot a/d\geq 0\)\(t\leq \lfloor \frac{y_0\cdot d}{a}\rfloor\).
    • 3、这里我第一次写的时候想的是,\(\lfloor m/y\rfloor\) 也是 \(\Theta(\sqrt m)\) 种取值,预处理出每一段 \(y\) 的范围,双指针扫描。但后面仔细想想,这里的 \(y\) 肯定是可以直接求解的(见后文)。
  • 可以得到一个 \(t\) 的取值范围 \(t\in [l_t,r_t]\)\(x+y=(x_0+y_0)\cdot \frac{k}{d} +\frac{t}{d}(b-a)\),很明显关于 \(t\) 单调,在端点取值即可

除法分块相关的不等式

  • \(\lfloor n/x\rfloor\) 只有 \(O(\sqrt n )\) 种取值,并且在 \(x\leq \sqrt n\) 时,\(x\) 每次变化都导致 \(\lfloor n/x\rfloor\) 不同;而在 \(x\geq \sqrt n\) 时,\(x\) 改变 \(1\) 至多导致 \(\lfloor n/x\rfloor\) 变化 \(1\).

一些相关的不等式:

  • 1、对于不等式 \(\lfloor n/x\rfloor\geq v\),有 \(n/x\geq \lfloor n/x\rfloor\geq v\),得到 \(x\leq \lfloor n/v\rfloor\),可以得到一个 \(x\) 的上界,同时代入 \(\lfloor n/v\rfloor\),会有 $$\lfloor \frac{n}{\lfloor n/v\rfloor}\rfloor\geq \lfloor\frac{n}{n/v}\rfloor=\lfloor v\rfloor=v$$同时 $$\lfloor\frac{n}{\lfloor n/v\rfloor +1}\rfloor>\lfloor \frac{n}{n/v}\rfloor=v$$
    因此 \(\lfloor n/x\rfloor\geq v\) 的解恰是 \(x\leq \lfloor n/v\rfloor\).

  • 2、对于不等式 \(\lfloor n/x\rfloor\leq v\),直接取 \(x\geq \lfloor n/v\rfloor\) 明显是不对的,例如 \(n=10,v=2\),当 \(x\geq 4\)\(\lfloor 10/x\rfloor \leq 2\),而 \(\lfloor 10/2\rfloor=5\)。应该考虑 $$\frac{n}{x}-1<\lfloor \frac{n}{x}\rfloor \leq v$$
    得到 $$\begin{aligned}\frac{n}{x}<v+1\ \Leftrightarrow\ x>\frac{n}{v+1}\ \Leftrightarrow\ x\geq \lfloor\frac{n}{v+1}\rfloor +1\end{aligned}$$
    这是一个下界,同时 $$\lfloor \frac{n}{\lfloor n/(v+1)\rfloor}\rfloor\geq \lfloor \frac{n}{n/(v+1)}\rfloor=v+1$$
    因此对不等式 \(\lfloor n/x\rfloor \leq v\) 的解应该恰是 \(\lfloor \frac{n}{v+1}\rfloor +1\),这是比较不同的地方。

题目代码

(写的还是双指针的写法)

#include<bits/stdc++.h>
#define endl '\n'
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
const ll INF=2e18;
int exgcd(ll &x,ll &y,int a,int b){
    if(!b){
        x=1;y=0;
        return a;
    }
    int d=exgcd(x,y,b,a%b);
    ll tx=x,ty=y;
    x=ty;y=tx-(a/b)*ty;
    return d;
}
int work(int n,int m,int a,int b,int k){
    //adjust
    ll x0,y0,d=exgcd(x0,y0,a,b);
    x0=x0*k/d;y0=y0*k/d;
    ll tx=(x0%(b/d)+(b/d))%(b/d),dd=(x0-tx)/(b/d);
    x0=x0-dd*(b/d);y0=y0+dd*(a/d);
    //solve
    ll ans=0;
    vector<int> seg;
    for(int y=1,pos;y<=m;y=pos+1){
        pos=min(m,m/(m/y));
        seg.push_back(pos);
    }
    int j=0;
    for(int x=1,R;x<=n;x=R+1){
        int L=x;
        R=min(n,n/(n/x));
        int lt=ceil((double)(L-x0)/(b/d));
        int rt=floor((double)(R-x0)/(b/d));

        while(j+1<seg.size()&&(m/seg[j+1])>=(n/x))j++;
        if(m/seg[j]<(n/x))continue;

        lt=max(lt,(int)ceil((double)(y0-seg[j])*d/a));
        rt=min(rt,(int)floor((double)y0*d/a));
        
        if(lt>rt)continue;
        ans=max(ans,(ll)(n/x)*(x0+y0+(ll)(b-a)/d*lt));
        ans=max(ans,(ll)(n/x)*(x0+y0+(ll)(b-a)/d*rt));
    }
    return ans;
}
int main(){
    fastio;
    int tc;cin>>tc;
    while(tc--){
        int n,m,a,b,k;
        cin>>n>>m>>a>>b>>k;
        cout<<n+m-max(work(n,m,a,b,k),work(m,n,b,a,k))<<endl;
    }
    return 0;
}
posted @ 2024-05-07 21:15  yoshinow2001  阅读(78)  评论(0编辑  收藏  举报