HDU - 6274 Master of Sequence (二分 + 公式推导)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6274

题目大意:给出一个长度为n的数组a和数组b,定义函数S(t)=\sum_{i = 1}^{n}\left \lfloor \frac{t-b[i]}{a[i]} \right \rfloor

接下来有m次操作,操作有如下三种:

1 x y :令 a[x] = y

2 x y :令b[x] = y

3 k : 找出最小的 t ,使其满足S(t)>=k,并输出t。

题目思路:要解决这个题目,得抓住题目中给出的两个关键条件:

1、对于任意的 a[i] 均小于等于1000 ;2、操作3的数量小于等于1000。

对于原式子S(t)=\sum_{i = 1}^{n}\left \lfloor \frac{t-b[i]}{a[i]} \right \rfloor,我们可以令t=k_{1}*a[i]+c_{1}b[i]=k_{2}*a[i]+c_{2},则原式子对于第i项可以化为,

\left \lfloor \frac{k_{1}*a[i]+c_{1}-(k_{2}*a[i]+c_{2})}{a[i]}\right \rfloor,即(k_{1}-k_{2} + \frac{c_{1}-c_{2}}{a[i]})

当c1 >= c2 时,第 i 项的值为k1 - k2,

当c1 < c2 时,第i 项的值为k1 - k2-1

所以S(t)=\sum_{i=1}^{n}(k_{1i}-k_{2i}+(c_{1i}<c_{2i})

由于是要求最小满足条件的 t ,我们自然可以考虑用二分来解决了。

由于 b[i] 的值和 a[i] 的值是固定的,所以我们可以通过预处理来求出\sum_{i=1}^{n}k_{2i}的值,移项一下,就变成了求满足

\sum_{i=1}^{n}(k_{1i}-(c_{1i}<c_{2i}))>=k+\sum_{i=1}^{n}k_{2i}的 t 了。

在二分check的时候,由于 t 已经是已知的了,那么k_{1i}也是固定的了,我们现在只需要考虑那些c_{1i}<c_{2i}的情况,减掉这些情况就行了。

由于a[i]<=1000,我们就可以用数组 cnt[i][j] 表示a[x] == i 同时 b[x]%a[x] >= j的个数有多少个,cnt数组可以直接预处理处理。

这样对于每个c_{1i},我们只用cnt数组就可以找出有多少个c_{2i}>c_{1i}。再将这些情况减去即可。

具体实现看代码:

#include <bits/stdc++.h>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define lowbit(x) x&-x
#define clr(a) memset(a,0,sizeof(a))
#define _INF(a) memset(a,0x3f,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define IOS ios::sync_with_stdio(false)
#define fuck(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
typedef pair<ll, ll>pll;
typedef pair<double, int> pdi;
const int mod = 998244353;
const int MX = 1e5 + 7;
const int inf = 0x3f3f3f3f;

int n, m, T;
int a[MX], b[MX];
ll cnt[1005][1005];

bool check(ll t, ll x) {
    ll res = 0;
    for (int i = 1; i <= 1000; i++) {
        res += t / i * cnt[i][0];
        res -= cnt[i][t % i + 1];
    }
    return res >= x;
}

ll solve(ll x) {
    ll l = 1, r = 1e13;
    ll ans = 0;
    while (l <= r) {
        ll mid = (l + r) >> 1;
        if (check(mid, x)) {
            ans = mid;
            r = mid - 1;
        }
        else l = mid + 1;
    }
    return ans;
}

int main() {
    // FIN;
    cin >> T;
    while (T--) {
        scanf("%d%d", &n, &m);
        clr(cnt);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        ll res = 0;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &b[i]);
            res += b[i] / a[i];
            cnt[a[i]][b[i] % a[i]]++;
        }
        for (int i = 1; i <= 1000; i++) {
            for (int j = i - 1; j >= 0; j--)
                cnt[i][j] += cnt[i][j + 1];
        }
        int op, x, y, k;
        while (m--) {
            scanf("%d", &op);
            if (op == 1) {
                scanf("%d%d", &x, &y);
                for (int i = b[x] % a[x]; i >= 0; i--)
                    cnt[a[x]][i]--;
                for (int i = b[x] % y; i >= 0; i--)
                    cnt[y][i]++;
                res -= b[x] / a[x]; res += b[x] / y;
                a[x] = y;
            } else if (op == 2) {
                scanf("%d%d", &x, &y);
                for (int i = b[x] % a[x]; i >= 0; i--)
                    cnt[a[x]][i]--;
                for (int i = y % a[x]; i >= 0; i--)
                    cnt[a[x]][i]++;
                res -= b[x] / a[x]; res += y / a[x];
                b[x] = y;
            } else {
                scanf("%d", &k);
                printf("%lld\n", solve((ll)res + k));
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Lee_w_j__/article/details/82949730
今日推荐