【Cf Edu #47 G】Allowed Letters

本文探讨了在特定字符限制下构建最小字典序字符串的贪心算法,通过网络流模型理解和验证解的存在性,最终提出了一个高效简洁的算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个题大概就是每一个位置都有一个能填字符的限制(一个点集),给出已有的$n$个字符,问能填出的最小字典序的字符串。

总体思路是贪心,每一位尽量选最小的字符。

关键在于判断在某位选了一个字符后,接下来的位置能否满足限制。

考虑怎么判断有解,这里有一种网络流的思路:

  1. 有$6$个点,代表了$a - f$$6$个字符,有源点向这些点连边,流量为该字符的个数。
  2. 另有$2^{6}$个点,代表了各个点集,这些点向汇点连边,流量为该点集在所有限制中出现的次数。
  3. 如果某个点在一个点集中,则由该点向该点集连流量为$INF$的边。

易得,当流量满流时,有合法解。

当然,用网络流这个模型虽然很容易理解,但如果每一次检验都跑一边的话效率不行,出题人有一种基于调整法的网络流做法,在已知流网络上进行修改,但是我不是很懂,代码也较长,在此不做累述。

此处所用的做法十分简洁。有以下结论:

  1. 接下来仅考虑某位置选了某个字符后,判断剩下的一个后缀是否有解。
  2. 定义$cnt_{i}$表示字符$i$的剩余数量,$num_{s}$表示与集合$s$有交的位置(该位置上限制的字符集与$s$有交)。
  3. 枚举$2^{6}$个集合,当所有的集合都准合法时才有解。
  4. 准合法的定义是:$\sum_{i = a}^{f} (其中 i \in s) <= num_{s}$。

显然,如果$|s|=1$,即$s$中只有一个字符,那$s$准合法就是$s$合法(存在合法解)。

这里用于说明$s$是合法的当且仅当所有$s$的子集是合法的,且$s$是准合法的。

由于我们从小到大枚举所有集合,可以保证所有之前已经枚举过的集合已经合法了,即它的子集都合法,故只要判断该集合是否准合法。

关于这个条件的必要性:

  1. 如果$s$不是准合法的,显然$s$不会是合法的,因为没有足够位置放。
  2. 如果$s$的某一个子集$s_{i}$不合法,也就是$s_{i}$的有关位置$num_{s_{i}}$不够调计,那在$s$的有关位置$num_{s}$中并不会有更多的供$s_{i}$中的字符放置的位置,那$s$也将是不合法的。

关于这个条件的充分性:

  1. 如果所有它的子集都合法了,并且$s$准合法,就不会存在某一个集合中的元素占用了过多的公共位置,因为那样会导致另一个子集不合法,即产生矛盾。

这样的话就能在$O(nA2^{A})$解决问题了,其中$A$是字符集大小。

 

$\bigodot$技巧与套路:

  • 利用网络流的模型
  • 集合的枚举以及使用
  •  1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 
     5 const int N = 100005, ST = 63;
     6 
     7 int n, m, bit[N], ans[N], cnt[7], num[ST + 2][N];
     8 char s[N], ssr[9];
     9 
    10 inline int Check(int x) {
    11     for (int st = 0; st <= ST; ++st) {
    12         int cnum = 0;
    13         for (int i = 0; i < 6; ++i) {
    14             if ((st >> i) & 1) cnum += cnt[i];
    15         }
    16         if (num[st][n] - num[st][x] < cnum) return 0;
    17     }
    18     return 1;
    19 }
    20 
    21 int main() {
    22     scanf("%s%d", s + 1, &m);
    23     n = strlen(s + 1);
    24     for (int i = 1; i <= n; ++i) {
    25         bit[i] = ST; ans[i] = -1;
    26         ++cnt[s[i] - 'a'];
    27     }
    28     for (int i = 1, x; i <= m; ++i) {
    29         scanf("%d%s", &x, ssr);
    30         int le = strlen(ssr), st = 0;
    31         for (int j = 0; j < le; ++j) {
    32             st |= 1 << (ssr[j] - 'a');
    33         }
    34         bit[x] &= st;
    35     }
    36     
    37     for (int st = 0; st <= ST; ++st) {
    38         for (int i = 1; i <= n; ++i) {
    39             num[st][i] = num[st][i - 1] + (bool)(bit[i] & st);
    40         }
    41     }
    42     
    43     for (int i = 1; i <= n; ++i) {
    44         for (int j = 0; j < 6; ++j) {
    45             --cnt[j];
    46             if (((bit[i] >> j) & 1) && Check(i)) {
    47                 ans[i] = j; break;
    48             }
    49             ++cnt[j];
    50         }
    51         if (ans[i] == -1) {
    52             puts("Impossible");
    53             return 0;
    54         }
    55     }
    56     for (int i = 1; i <= n; ++i) {
    57         putchar(ans[i] + 'a');
    58     }
    59     
    60     return 0;
    61 }
    View Code

     

转载于:https://www.cnblogs.com/Dance-Of-Faith/p/9320822.html

<think>我们正在讨论单臂路由的配置,用户现在询问交换机配置命令的具体作用 用户问题:`Switch config-if switchport trunk allowed vlan 10 20` 命令的作用是什么? 根据引用[1]和引用[2]的内容,我们知道在配置VLAN时,需要将交换机连接路由器的端口设置为Trunk模式,并且需要指定允许通过的VLAN。 命令解释: 该命令用于配置交换机端口的Trunk模式,并指定允许通过的VLAN列表。具体来说: - `switchport trunk allowed vlan 10,20` 表示该Trunk端口只允许VLAN 10和VLAN 20的流量通过。 在单臂路由的配置中,交换机通过Trunk端口连接路由器,而路由器需要处理多个VLAN(如VLAN10和VLAN20)的流量,因此交换机上连接路由器的端口必须允许这些VLAN的流量通过。 详细说明: 1. Trunk端口的作用:在交换机之间或交换机与路由器之间传输多个VLAN的流量时,需要使用Trunk端口,它通过给数据帧打上VLAN标签(如802.1Q)来区分不同VLAN的流量。 2. `allowed vlan`参数:该参数用于限制哪些VLAN的流量可以通过这个Trunk端口。如果不配置,默认允许所有VLAN通过(但在实际配置中,我们通常显式指定允许的VLAN以增强安全性和控制)。 因此,在单臂路由的配置中,该命令确保只有VLAN10和VLAN20的流量能够从交换机传递到路由器,其他VLAN的流量则被阻止。 注意:命令中的VLAN列表可以是一个或多个VLAN,多个VLAN之间用逗号分隔,也可以使用范围(如10-20)。 引用说明: 根据引用[1]中提到的Trunk配置思路,以及引用[2]中关于VLAN间路由的配置,该命令是配置VLAN间路由(如单臂路由)的关键步骤之一。 现在,我们可以这样回答用户:</think>`switchport trunk allowed vlan 10,20` 命令在交换机配置中起到**关键过滤作用**,其核心功能是:**限制Trunk端口仅允许特定VLAN流量通过**。具体作用如下: ### 一、命令解析 ```cisco Switch(config-if)# switchport trunk allowed vlan 10,20 ``` - **`switchport trunk`**:声明端口工作模式为Trunk(干道) - **`allowed vlan`**:定义流量过滤规则 - **`10,20`**:指定允许通过的VLAN ID列表(此处为VLAN 10和20) ### 二、核心作用 1. **VLAN流量过滤** - 仅允许VLAN 10和20的流量通过该Trunk端口 - 其他VLAN(如VLAN 30,40等)流量将被**自动丢弃** 2. **安全隔离** - 防止未授权VLAN访问核心网络(如阻止部门间越权访问) - 减少广播域范围,避免不必要流量泛洪[^1] 3. **带宽优化** - 避免无关VLAN占用链路带宽(如阻塞管理VLAN流量) - 确保关键业务VLAN(如语音/视频)获得稳定带宽[^3] ### 三、应用场景(以单臂路由为例) ```mermaid graph LR A[PC1-VLAN10] --> B[交换机] C[PC2-VLAN20] --> B B -- Trunk端口<br>仅放行VLAN10/20 --> D[路由器] ``` - 当交换机连接路由器实现单臂路由时: 1. 路由器只需处理VLAN 10/20的流量 2. 此命令确保**仅需转发的VLAN到达路由器** 3. 避免路由器收到无关VLAN数据包造成资源浪费 ### 四、扩展配置技巧 1. **添加/删除VLAN** ```cisco ! 添加VLAN30到允许列表 Switch(config-if)# switchport trunk allowed vlan add 30 ! 移除VLAN10 Switch(config-if)# switchport trunk allowed vlan remove 10 ``` 2. **批量操作VLAN范围** ```cisco ! 允许VLAN10-50 Switch(config-if)# switchport trunk allowed vlan 10-50 ! 排除VLAN25 Switch(config-if)# switchport trunk allowed vlan except 25 ``` 3. **恢复默认配置** ```cisco ! 允许所有VLAN通过(默认行为) Switch(config-if)# switchport trunk allowed vlan all ``` > **关键验证命令**: > ```cisco > Switch# show interfaces trunk // 查看Trunk端口允许的VLAN列表 > Port Vlans allowed on trunk > Gi0/1 10,20 // 确认仅VLAN10/20被允许 > ``` ### 五、与相关概念对比 | 配置命令 | 作用 | 单臂路由中的必要性 | |-----------------------------------|--------------------------------|------------------| | `switchport mode trunk` | 启用Trunk模式 | 必需 | | `switchport trunk allowed vlan` | **限制可通过的VLAN** | 强烈推荐 | | `switchport trunk native vlan` | 设置本地VLAN(不打标签) | 可选 | > **最佳实践**:在单臂路由中显式配置`allowed vlan`可提升安全性和性能,避免路由器处理无关VLAN的ARP请求等流量[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值