Codeforces Round 855 (Div. 3) F. Dasha and Nightmares(题解 + 详细思考过程讲解)

F. Dasha and Nightmares(二进制)

链接:F. Dasha and Nightmares

题目最重要的破题点思路 即第4点 由某银牌佬提供,唉膜拜大佬。

题意

给定 n n n 个字符串, ( 1 < = n < = 2 ∗ 1 0 5 ) (1 <=n<=2 * 10^5) 1<=n<=2105 字符串长度之和不超过 5 ∗ 1 0 6 5 *10^6 5106
求字符串对 s i , s j si,sj si,sj个数,要满足以下条件
条件1.拼接后恰好有 25 25 25 种字母。
条件2.拼接后每个字母个数为奇数。

题解 + 思考过程

1. 最开始想到用二进制,将每个字符串转化为一个长度为 26 26 26 的二进制数,字符 c h ch ch 的个数, 奇数 = 1 =1 =1 ,偶数 = 0 =0 =0
例如 s t r = " a " str = "a" str="a" 二进制串 = 1000 … … = 1000…… =1000…… s t r = " a b " = 1100 … … str = "ab" = 1100…… str="ab"=1100…… s t r = " a a b " = 0100 … … str = "aab" = 0100…… str="aab"=0100……
对于条件1:可以想到对于每个字符串枚举哪一个字符舍去。
对于条件2:用位运算直接去找到合法的,异或全 1 1 1 二进制数再减去应该舍去的字符位上的1。

2. 但是必须只有 25 25 25 个,但是偶数对应 0 0 0, 那么不知道该字符是否有,因为没有该字符为 0 0 0 也对应 0 0 0
例如枚举字符 a a a 没有, 但字符串 s t r = " a a " str = "aa" str="aa" ,那么该字符串代表的二进制为全 0 0 0,就可以和 字符串 " b ∼ z " "b\sim z" "bz" 拼接 但拼接后有 26 26 26个字母,显然不合法。

3. 于是想到用三进制来表示, 0 = 0 0 = 0 0=0, 奇数 = 1 = 1 =1 大于 0 0 0 的偶数 = 2 = 2 =2, 用字典树去计算
但是由于 1 1 1 对应 0 0 0 2 2 2 (字符串该位上为 1 1 1,那么该位上为 0 0 0 2 2 2 的都可以与之拼接)
这样递归时间复杂度可能达到 2 2 2 的幂次方级别。不可行。

4. 最后想到 枚举的不存在的那个字符,只有两个字符串都没有该字符才能拼接后满足。
所以我们可以每次遍历不存在 字符 c h ch ch 的字符串集合,这样就不用考虑该位的 0 0 0 是大于 0 0 0 的偶数还是 0 0 0 的问题了。
因为除了我们枚举的该位必须不存在的其他字符 都必须为奇数,所以至少存在,对应拼接的是 0 0 0 还是大于 0 0 0 的偶数就无所谓了。
可以直接采取1.做法,不过需要在每次计算后清除贡献。(如果不清除,影响可以参考2.)。

代码

#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
const int N = 2e5 + 10, M = 1 << 26;
const int K = (1 << 26) - 1;//长度为26的全1二进制数
string s[N];
int t[N], val[M];//t[i]:转化后二进制数 val[i]:计数
vector<int>g[26];//g[i]:没有字符i的字符串的下标
int main()
{
    ios::sync_with_stdio(false);
    cout.tie(NULL);

    int n;
    cin >> n;
    for(int i = 1; i <= n; i ++){
        cin >> s[i];
        int len = s[i].length();
        int vis[30] = {0};
        for(int j = 0; j < len; j ++){
            vis[s[i][j] - 'a'] ++;
        }
        int num = 0;
        for(int j = 0; j < 26; j ++){
            if(vis[j] & 1) num += (1 << j);
            if(!vis[j]) g[j].push_back(i);
        }
        t[i] = num;
    }
    
    ll ans = 0;
    for(int i = 0; i < 26; i ++){//枚举没有i字符的字符串,只有都没有某个字符的字符串才能匹配
        for(int id : g[i]){
            val[t[id]] ++;
            int v = t[id] ^ K ^ (1 << i);//能与si拼接的字符串所代表的二进制数
            ans += val[v];
        }
        for(int id : g[i]) val[t[id]] --;//清除贡献
    }
    cout << ans;
    return 0;
}
### Codeforces Round 927 Div. 3 比赛详情 Codeforces是一个面向全球程序员的比赛平台,定期举办不同级别的编程竞赛。Div. 3系列比赛专为评级较低的选手设计,旨在提供更简单的问题让新手能够参与并提升技能[^1]。 #### 参赛规则概述 这类赛事通常允许单人参加,在规定时间内解决尽可能多的问题来获得分数。评分机制基于解决问题的速度以及提交答案的成功率。比赛中可能会有预测试案例用于即时反馈,而最终得分取决于系统测试的结果。此外,还存在反作弊措施以确保公平竞争环境。 ### 题目解析:Moving Platforms (G) 在这道题中,给定一系列移动平台的位置和速度向量,询问某时刻这些平台是否会形成一条连续路径使得可以从最左端到达最右端。此问题涉及到几何学中的线段交集判断和平面直角坐标系内的相对运动分析。 为了处理这个问题,可以采用如下方法: - **输入数据结构化**:读取所有平台的数据,并将其存储在一个合适的数据结构里以便后续操作。 - **时间轴离散化**:考虑到浮点数精度误差可能导致计算错误,应该把整个过程划分成若干个小的时间间隔来进行模拟仿真。 - **碰撞检测算法实现**:编写函数用来判定任意两个矩形之间是否存在重叠区域;当发现新的连接关系时更新可达性矩阵。 - **连通分量查找技术应用**:利用图论知识快速求解当前状态下哪些节点属于同一个集合内——即能否通过其他成员间接相连。 最后输出结果前记得考虑边界条件! ```cpp // 假设已经定义好了必要的类和辅助功能... bool canReachEnd(vector<Platform>& platforms, double endTime){ // 初始化工作... for(double currentTime = startTime; currentTime <= endTime ;currentTime += deltaT){ updatePositions(platforms, currentTime); buildAdjacencyMatrix(platforms); if(isConnected(startNode,endNode)){ return true; } } return false; } ```
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值