链接:F. Dasha and Nightmares
题目最重要的破题点思路 即第4点 由某银牌佬提供,唉膜拜大佬。
给定 nnn 个字符串,(1<=n<=2∗105)(1 <=n<=2 * 10^5)(1<=n<=2∗105) 字符串长度之和不超过 5∗1065 *10^65∗106。
求字符串对si,sjsi,sjsi,sj个数,要满足以下条件
条件1.拼接后恰好有 252525 种字母。
条件2.拼接后每个字母个数为奇数。
1. 最开始想到用二进制,将每个字符串转化为一个长度为 262626 的二进制数,字符 chchch 的个数, 奇数 =1=1=1 ,偶数 =0=0=0
例如 str="a"str = "a"str="a" 二进制串 =1000……= 1000……=1000……, str="ab"=1100……str = "ab" = 1100……str="ab"=1100……, str="aab"=0100……str = "aab" = 0100……str="aab"=0100……
对于条件1:可以想到对于每个字符串枚举哪一个字符舍去。
对于条件2:用位运算直接去找到合法的,异或全 111 二进制数再减去应该舍去的字符位上的1。
2. 但是必须只有 252525 个,但是偶数对应 000, 那么不知道该字符是否有,因为没有该字符为 000 也对应 000。
例如枚举字符 aaa 没有, 但字符串 str="aa"str = "aa"str="aa" ,那么该字符串代表的二进制为全 000,就可以和 字符串 "b∼z""b\sim z""b∼z" 拼接 但拼接后有262626个字母,显然不合法。
3. 于是想到用三进制来表示,0=00 = 00=0, 奇数 =1= 1=1 大于 000 的偶数 =2= 2=2, 用字典树去计算
但是由于 111 对应 000 和 222 (字符串该位上为 111,那么该位上为 000 或 222 的都可以与之拼接)
这样递归时间复杂度可能达到 222 的幂次方级别。不可行。
4. 最后想到 枚举的不存在的那个字符,只有两个字符串都没有该字符才能拼接后满足。
所以我们可以每次遍历不存在 字符 chchch 的字符串集合,这样就不用考虑该位的 000 是大于 000 的偶数还是 000 的问题了。
因为除了我们枚举的该位必须不存在的其他字符 都必须为奇数,所以至少存在,对应拼接的是 000 还是大于 000 的偶数就无所谓了。
可以直接采取1.做法,不过需要在每次计算后清除贡献。(如果不清除,影响可以参考2.)。
#include
#include
#include
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]:计数
vectorg[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;
}