CDOJ 761 LoveZx与期末考试 【数学贪心+二分】

题目链接:CDOJ 761 LoveZx与期末考试

题意:给定两个大整数 a b ,每次可以将 b 的一个十进制位移到前面的任一个位置。问最少需要多少次操作使得 b>a

思路:直接模拟是可以做的,但不过太过复杂。我们尝试去二分这个最优解,对当前的判定值 mid ,我们只需要求出 b mid 次修改的前提下可以得到的最大值。

假设 n 位的整数 a=a[1]a[2]...a[n] ,它可以得到的最大数为 b=b[1]...b[n]
考虑移动 a[1]a[n] 里面前 mid 大的数到高位:
我们不能只移动前 mid 大的数,因为 a[1]==b[1] 同理 a[2] 。假设从第一位开始有 num 个连续位满足 a[i]==b[i] ,这样的话,这 num 个数是不需要移动的,因为已经是最优了。也就是说,对当前的 mid 次移动,我们可以看做是移动 a[1]a[n] 里面前 (mid+num) 大的数到高位。然后就是把剩余的数按原顺序填上,这样就得到了移动 mid 次的最优值。填数的时候,需要把移动的 mid 个数标记上。

这样时间复杂度 O(nlogn)
AC 代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define PI acos(-1.0)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define fi first
#define se second
#define ll o<<1
#define rr o<<1|1
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int pN = 1e6;// <= 10^7
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
void getmax(int &a, int b) {a = max(a, b); }
void getmin(int &a, int b) {a = min(a, b); }
void add(LL &x, LL y) { x += y; x %= MOD; }
int a[MAXN], b[MAXN];
char x[MAXN], y[MAXN];
int lx, ly;
bool cmp(int x, int y) {
    return x > y;
}
void get(int *c, char s[]) {
    int len = strlen(s);
    for(int i = 0; i < len; i++) c[i] = s[i] - '0';
}
int d[MAXN], c[MAXN], use[10];
bool judge(int cnt, int num)
{
    if(lx < ly) return true;
    else if(lx > ly) return false;
    for(int i = 0; i <= 10; i++) {
        use[i] = 0;
    }
    CLR(d, 0);
    for(int i = 0; i < min(ly, cnt+num); i++) {
        d[i] = c[i];
        if(i >= num) {
            use[c[i]]++;
        }
    }
    int top = ly-1;
    for(int i = ly-1; i >= 0 && top >= min(ly, cnt+num); i--) {
        if(use[b[i]]) {
            use[b[i]]--;
        }
        else {
            d[top--] = b[i];
        }
    }
//    cout << cnt << endl;
//    for(int i = 0; i < ly; i++) {
//        cout << d[i] << ' ';
//    }
//    cout << endl;
    for(int i = 0; i < ly; i++) y[i] = d[i] + '0';
    return strcmp(y, x) > 0;
}
int main()
{
    int t; scanf("%d", &t);
    while(t--)
    {
        scanf("%s%s", x, y);
        lx = strlen(x), ly = strlen(y);
        CLR(a, 0); CLR(b, 0); CLR(c, 0);
        get(a, x); get(b, y);
        for(int i = 0; i < ly; i++) {
            c[i] = b[i];
        }
        sort(c, c+ly, cmp); int num = 0;
        for(int i = 0; i < ly; i++) {
            if(c[i] == b[i]) {
                num++;
            }
            else break;
        }
        int l = 0, r = ly;
        int ans = -1;
        while(r >= l) {
            int mid = (l + r) >> 1;
            if(judge(mid, num)) {
                ans = mid;
                r = mid-1;
            }
            else {
                l = mid+1;
            }
        }
        if(ans == -1) {
            printf("Poor LoveZx\n");
        }
        else {
            printf("%d\n", ans);
        }
    }
    return 0;
}

你可能感兴趣的:(贪心,数学,二分)