题解 2023.10.22

P6739 [BalticOI 2014 Day1] Three Friends
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    
    int n;
    cin >> n;
    string s, l, r;
    cin >> s;

    if(n % 2 == 0) {
    	cout << "NOT POSSIBLE\n";
    	return 0;
    }

    int m = n / 2;

    //在s中删除一个字符,使得左右两边相等,并且能够得到的答案子串是唯一的。
    //用左半段l和s-l(右边所有)进行逐位匹配,就相当于在s-l中删除了一个字符能否与l相同。
    //用右半段时,也是同理。

    l = s.substr(0, m);
    r = s.substr(n - m, m);

    bool f1 = false, f2 = false;

    int j = 0;
    for (int i = m; i < n && j < m; i++) {
        if(s[i] == l[j]) j++;
    }
    if(j == m) f1 = true;

    j = 0;
    for (int i = 0; i < n - m && j < m; i++) {
        if(s[i] == r[j]) j++;
    }
    if(j == m) f2 = true;

    if(!f1 && !f2) {
        cout << "NOT POSSIBLE\n";
    }
    else if(f1 && f2 && l != r) {
        cout << "NOT UNIQUE\n";
    }
    else if(f1) cout << l << endl;
    else cout << r << endl;
    
    return 0;
}
cf821 D2. Zero-One (Hard Version)


题目大意:给定长度为n(n <= 5000)的两个01字符串a,b,现在你可以进行
的操作为:选择两个索引l < r,若l + 1 == r花费x, 否则花费y。
问使得a,b相等需要的最小花费。

记录a,b不相等处的索引,个数为奇输出-1。
x >= y简单,贪心:尽可能的选择不相邻的l和r。
x < y,贪心:尽可能选择相邻的或最近的。
记忆化搜索:
1.选择l和l+1,2.选择r和r-1,3.选择l和r,想当于想让后续索引的选择更加接近。

using ll = long long;
const ll inf = 1e18;

ll f[5005][5005], n, x, y;
int id[5005], p;

ll dfs(int l, int r) {
	if(l > r) return 0;
	if(f[l][r] != -1) return f[l][r];
	ll ans1 = dfs(l + 2, r) + min(y, x * (id[l + 1] - id[l]));
	ll ans2 = dfs(l + 1, r - 1) + min(y, x * (id[r] - id[l]));
	ll ans3 = dfs(l, r - 2) + min(y, x * (id[r] - id[r - 1]));
	return f[l][r] = min({ans1, ans2, ans3});
}

void solve() {
	cin >> n >> x >> y;
	string a, b;
	cin >> a >> b;
	for (int i = 0; i < n; i++) {
		if(a[i] != b[i]) {
			id[p++] = i;
		}
	}
	if(p & 1) {
		p = 0;
		cout << -1 << endl;
		return;
	}
	ll ans = 0;
	if(x >= y) {
		int xt = 0;
		for (int i = 0; i < p; i += 2) {
			if(id[i] + 1 == id[i + 1]) {
				xt++;
			}
		}
		int ct = p / 2 - xt;
		if(xt == 1 && !ct) {
			ans = min(x, 2 * y);
		}
		else {
			ans = xt * y + ct * y;
		}
		cout << ans << "\n";
		p = 0;
		return;
	}
	for (int i = 0; i < p; i++) {
		for (int j = 0; j < p; j++) {
			f[i][j] = -1;
		}
	}
	cout << dfs(0, p - 1) << endl;
	p = 0;
} 
cf 899 div2 D


题目大意:给你一棵树(n个顶点,n - 1条边),每一个顶点的值为a[i],你需要求得的是每一个顶点为
根得时候,要使得所有顶点的值相等,需要付出的最小代价。
子树:假设选择顶点r作为树根。如果从i到r的简单路径包含v,那么顶点i属于v的子树。
你可以进行的操作:选定一个顶点v和一个非负整数c,把v的子树中的所有顶点的值异或上c,花费的
代价为sz[v]*c,sz[v]是子树的大小。

贪心:以哪个顶点为根,就把其余的所有顶点的值变成和根的值相同。
我们可以先求出以1为根结点所花费的代价,然后进行换根。
换根:又父节点u换到子节点v:ans[v] = ans[u] + 1LL * (n - sz[v] * 2) * (a[u] ^ a[v])。
相当于此时u的子树需要再算一次(u的子树的大小即为n-sz[v]),而v的子树不需要算了(v之前算了,所以要减去)。

void solve() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }

    vector<vector<int> > g(n);
    for (int i = 0; i < n - 1; i++) {
        int u, v;
        cin >> u >> v;
        u--, v--;
        g[u].push_back(v);
        g[v].push_back(u);
    }

    vector<ll> ans(n), sz(n);
    auto dfs1 = [&](auto self, int u, int fa) -> void {
        sz[u] = 1;
        for (int v : g[u]) {
            if(v == fa) continue;
            self(self, v, u);
            sz[u] += sz[v];
            ans[0] += sz[v] * (a[u] ^ a[v]);
        }
    };
    dfs1(dfs1, 0, -1);

    auto dfs2 = [&](auto self, int u, int fa) -> void {
        for (int v : g[u]) {
            if(v == fa) continue;
            ans[v] = ans[u] + 1LL * (n - sz[v] * 2) * (a[u] ^ a[v]);
            self(self, v, u);
        }
    };
    dfs2(dfs2, 0, -1);

    for (int i = 0; i < n; i++) {
        cout << ans[i] << " \n"[i == n - 1];
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

akb000

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值