CF1383C 题解

本篇博客详细分析了CF1383C问题,通过将同色视为同一元素,构建图并寻找最小边数的联通图。题目要求边变化时间递增,最优解是一个环加链结构。采用动态规划策略,对每个弱连通块分别计算形成最大DAG所需的最少点数,确保无环。最终,通过枚举所有可能的点集确保了DP的正确性。

CF1383C

观察一下题目的性质,他说了同一种颜色可以有若干个一起变色,那么我们考虑将同一种颜色看成相同的东西。

考虑对于其建图,也就是如果 A i A_i Ai 变成 B i B_i Bi 就建立 A i → B i A_i \to B_i AiBi 的边。

然后本质上就是叫我们重新建立一张图满足 A i A_i Ai B i B_i Bi 联通,边数最少的图。

本质上每一次变换都是需要一次操作。

但是不仅是如此,如果说 u → v u \to v uv 的路径是存在的,必须满足其路径上的边的变化时间是递增的。那么就是让我们对于边进行标号,然后满足图上任意路径都是递增的。

我们发现如果任意两个点都能互相到达,边数最少的就是一个环加上一条链。也就是这样的情况。
flvHxI.png
这样我们需要消耗 2 n − 2 2n - 2 2n2 条边。

但是我们可以更优,也就是考虑对于这个图,找到一个最大的 D A G DAG DAG 进行向链一样连边,然后后面的点进行这样的操作。

flxowT.png

这样子肯定是最优的。
然后我们考虑通过 D p Dp Dp 计算这个答案,发现直接计算选了 S S S 中的点,最大 D A G DAG DAG 的大小不好算。那么我们就找下面链的最少点个数。

我们对于每一个弱连通块分别考虑,设 f ( S ) f(S) f(S) 表示考虑了集合 S S S 中的点,最少点个数为 f ( S ) f(S) f(S)。转移的时候看这个点和当前的点是否有连边即可,因为有连边说明会产生环。

可能有读者对于这个 D p Dp Dp 的正确性很疑惑,比如说点 x x x 都是出边,但是后面才枚举到,这样不是让其变成了环吗?本质上我们枚举了所有点集,从中选出一个最优的点集,所以这种情况会被更优的情况取代, D p Dp Dp 的正确性从而有保证。

#include <bits/stdc++.h>
using namespace std;

//#define Fread
// #define Getmod

#ifdef Fread
char buf[1 << 21], *iS, *iT;
#define gc() (iS == iT ? (iT = (iS = buf) + fread (buf, 1, 1 << 21, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
#endif // Fread

template <typename T>
void r1(T &x) {
	x = 0;
	char c(getchar());
	int f(1);
	for(; c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
	for(; '0' <= c && c <= '9';c = getchar()) x = (x * 10) + (c ^ 48);
	x *= f;
}

const int mod  = 1e9 + 7;
#ifdef Getmod
template <int mod>
struct typemod {
    int z;
    typemod(int a = 0) : z(a) {}
    inline int inc(int a,int b) const {return a += b - mod, a + ((a >> 31) & mod);}
    inline int dec(int a,int b) const {return a -= b, a + ((a >> 31) & mod);}
    inline int mul(int a,int b) const {return 1ll * a * b % mod;}
    typemod<mod> operator + (const typemod<mod> &x) const {return typemod(inc(z, x.z));}
    typemod<mod> operator - (const typemod<mod> &x) const {return typemod(dec(z, x.z));}
    typemod<mod> operator * (const typemod<mod> &x) const {return typemod(mul(z, x.z));}
    typemod<mod>& operator += (const typemod<mod> &x) {*this = *this + x; return *this;}
    typemod<mod>& operator -= (const typemod<mod> &x) {*this = *this - x; return *this;}
    typemod<mod>& operator *= (const typemod<mod> &x) {*this = *this * x; return *this;}
    int operator == (const typemod<mod> &x) const {return x.z == z;}
    int operator != (const typemod<mod> &x) const {return x.z != z;}
};
typedef typemod<mod> Tm;
#endif
template <typename T,typename... Args> inline void r1(T& t, Args&... args) {
    r1(t);  r1(args...);
}

// #define int long long
const int maxn = 20 + 5;
const int maxm = 1e5 + 5;
int vis[maxn];
int n;
char A[maxm], B[maxm];
int vc1[maxn][maxn];
void add(int u,int v) {
    ++ u, ++ v;
    vc1[u][v] = 1;
}
int vc[maxn][maxn];
int st[maxn], ed(0);
int E[maxn];
void dfs(int p) {
    vis[p] = 1, st[ed ++] = p;
    for(int j = 1; j <= 20; ++ j) if(vc1[p][j] && !vis[j]) dfs(j);
}

#define Online
signed main() {
#ifndef Online
    freopen("S.in", "r", stdin);
    freopen("S.out", "w", stdout);
#endif

    auto calc = [&] (void) {
        const int inf = 0x3f3f3f3f;
        int z = (1 << ed) - 1, i, j;
        for(i = 0; i < ed; ++ i) {
            E[i] = 0;
            for(j = 0; j < ed; ++ j) E[i] |= vc[st[i]][st[j]] << j;
        }
        vector<int> dp(z + 1, inf);
        dp[0] = 0;
        for(int S = 0; S <= z; ++ S) {
            for(int j = 0; j < ed; ++ j) if(!((S >> j) & 1)) {
                dp[S | (1 << j)] = min(dp[S | (1 << j)], dp[S] + !!(S & E[j]));
            }
        }
//        printf("dp[%lld] = %lld\n", ed, dp[z]);
        return dp[z] + ed - 1;
    };

    auto Solve = [&] (void) {
        int i, j;
        memset(vis, 0, sizeof(vis));
        memset(vc, 0, sizeof(vc));
        memset(vc1, 0, sizeof(vc1));
        r1(n);
        scanf("%s%s", A + 1, B + 1);
        for(i = 1; i <= n; ++ i) {
            vc[A[i] - 'a' + 1][B[i] - 'a' + 1] = 1;
            add(A[i] - 'a', B[i] - 'a'), add(B[i] - 'a', A[i] - 'a');
        }
        int ans(0);
        for(i = 1; i <= 20; ++ i) if(!vis[i]) {
            ed = 0;
            dfs(i);
            ans += calc();
//            printf("i = %lld\n", i);
        }
        printf("%d\n", ans);
//        puts("----\n");
    };

    int T;
    r1(T);
    while(T --) Solve();

	return 0;
}
/*
1
3
abc
tsr

3

*/

源码地址: https://pan.quark.cn/s/a4b39357ea24 欧姆龙触摸屏编程软件MPTST 5.02是专门为欧姆龙品牌的工业触摸屏而研发的编程解决方案,它赋予用户在直观界面上构建、修改以及排错触摸屏应用程序的能力。 该软件在工业自动化领域具有不可替代的地位,特别是在生产线监视、设备操控以及人机互动系统中发挥着核心作用。 欧姆龙MPTST(Machine Process Terminal Software Touch)5.02版本配备了多样化的功能,旨在应对不同种类的触摸屏项目要求。 以下列举了若干核心特性:1. **图形化编程**:MPTST 5.02采用图形化的编程模式,允许用户借助拖拽动作来设计屏幕布局,设定按钮、滑块、指示灯等组件,显著简化了编程流程,并提升了工作效率。 2. **兼容性**:该软件能够适配欧姆龙的多个触摸屏产品线,包括CX-One、NS系列、NJ/NX系列等,使用户可以在同一个平台上完成对不同硬件的编程任务。 3. **数据通信**:MPTST 5.02具备与PLC(可编程逻辑控制器)进行数据交互的能力,通过将触摸屏作为操作界面,实现生产数据的显示与输入,以及设备状态的监控。 4. **报警与事件管理**:软件中集成了报警和事件管理机制,可以设定多种报警标准,一旦达到预设条件,触摸屏便会展示对应的报警提示,助力操作人员迅速做出响应。 5. **模拟测试**:在设备实际连接之前,MPTST 5.02支持用户进行脱机模拟测试,以此验证程序的正确性与稳定性。 6. **项目备份与恢复**:为了防止数据遗失,MPTST 5.02提供了项目文件的备份及还原功能,对于多版本控制与团队协作具有显著价值。 7. **多语言支持**:针对全球化的应...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值