hdoj 5903 Square Distance 【贪心 + 数学】

无聊写了一发,莫名1A掉了。不知道题解 dp 怎么个写法 (ˇˍˇ) 想~
hdoj 5903 Square Distance
题意:给定一个偶数长度的字符串 str ,让你构造一个字典序最小的字符串 s ,使得两串中不同字符个数正好为m个,要求 s 串从中间截开后得到的两段字符串完全相同。

发现
str[i]!=str[i+n/2],那它们的贡献要么是1,要么是2;
str[i]==str[i+n/2] ,那它们的贡献要么是0,要么是2;

思路:考虑对于当前的状态 (i,j) 即第 i 个位置填字符j是否合法。
我们把 [i+1,n/2] 之后的字符分为两类
一、 str[j]!=str[j+n/2]
二、 str[j]==str[j+n/2]
记第一类数目为 num1 ,第二类数目为 num2
x1 为第一类里贡献为1的字符数目, x2 是贡献为2的字符数目。
x3 为第二类里贡献为0的字符数目, x4 是贡献为2的字符数目。
有方程组
x1+x2=num1
x3+x4=num2
x1+2x2+2x4=m(str[i]!=j)(str[i+n/2]!=j)

把第一个式子代入第三个有
num1+x2+2x4=m(str[i]!=j)(str[i+n/2]!=j)
x3+x4==num2
我们枚举 x2 的范围 0<=x2<=num1 ,看是否存在合法的 x3x4 使得 0<=x3,x4<=num2 x3+x4==num2
这样时间复杂度 O(n26n/2)

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <cstdlib>
#define ll o<<1
#define rr o<<1|1
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e3 + 10;
const int INF = 1e6 + 10;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MOD = 1e9 + 7;
char str[MAXN];
int a[MAXN];
int ans[MAXN];
int n, m;
bool judge(int pos, int val) {
    int num1 = 0, num2 = 0;
    for(int i = pos + 1; i <= n; i++) {
        if(a[i] != a[i + n]) { // 1 2
            num1++;
        }
        else { // 0 2
            num2++;
        }
    }
    for(int i = 0; i <= num1; i++) {
        int x4 = m - val - num1 - i;
        if(x4 % 2 == 0) {
            x4 /= 2; int x3 = num2 - x4;
            if(x3 >= 0 && x3 <= num2 && x4 >= 0 && x4 <= num2) return true;
        }
    }
    return false;
}
int main()
{
    int t; scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &m);
        scanf("%s", str + 1);
        for(int i = 1; i <= n; i++) {
            a[i] = str[i] - 'a';
        }
        n /= 2; bool flag = true;
        for(int i = 1; i <= n; i++) {
            bool yes = false;
            for(int j = 0; j <= 25; j++) {
                int cnt = 0;
                if(a[i] != j) {
                    cnt++;
                }
                if(a[i + n] != j) {
                    cnt++;
                }
                if(judge(i, cnt)) {
                    ans[i] = j;
                    m -= cnt;
                    yes = true; break;
                }
            }
            if(!yes) {
                flag = false;
                break;
            }
        }
        if(!flag) {
            printf("Impossible\n");
        }
        else {
            for(int i = 1; i <= n; i++) {
                printf("%c", 'a' + ans[i]);
            }
            for(int i = 1; i <= n; i++) {
                printf("%c", 'a' + ans[i]);
            }
            printf("\n");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值