AGC026_C 题解
题意简述
给出一个长度为
题目分析
折半搜索的经典题了吧。
很明显直接枚举染色情况时间复杂度会炸,所以我们考虑更优的做法。
我们先来看看什么是折半搜索。
双向同时搜索(折半搜索,又称 Meet in the middle 算法)的基本思路是从状态图上的起点和终点同时开始进行广搜或深搜。如果发现搜索的两端相遇了,那么可以认为是获得了可行解。
暴力搜索的复杂度往往是指数级的,而改用折半搜索后复杂度的指数可以减半,即让复杂度从
降到 。 ——OI Wiki
本题就可以采用折半搜索。具体来说,可以将
得到
又有
也就是说,前半段的红串是后半段的蓝串的反串,前半段的蓝串是后半段红串的反串(本部分证明参考了 Ezio__Auditore 大佬的题解,在此膜拜大佬)
那么我们就可以先在前半段暴力枚举每个字母的染色情况,把红串和蓝串一起哈希一下存到哈希表里(可以通过 map
实现);然后在后半段倒着暴力枚举字母的染色情况,把蓝串和红串一起哈希一下,把哈希表里的方案数加到答案里。
最后就是字符串哈希的实现。本题字符串较短,冲突概率相对较小,因此只需要把字符串看作一个 unsigned long long
存储,这样自然溢出就可以实现对
代码实现
#include <bits/stdc++.h> using namespace std; #define ull unsigned long long map<pair<ull,ull>,int>mp;//哈希表 int n; long long ans; string s[2]; void dfs(int x,ull hs1/*红串哈希值*/,ull hs2/*蓝串哈希值*/,bool fg) { if(x>n) { if(fg) ans+=mp[{hs1,hs2}];//统计方案数 else mp[{hs2,hs1}]++; //前半段的红串蓝串丢到哈希表里 return; } dfs(x+1,hs1*131ull/*一个质数 p*/+s[fg][x-1],hs2,fg);//第 x 个字符染成红的 dfs(x+1,hs1,hs2*131ull+s[fg][x-1],fg);//第 x 个字符染成蓝的 } int main() { ios::sync_with_stdio(0); cin.tie(); cout.tie(); cin>>n>>s[0]; s[1]=s[0].substr(n,n); reverse(s[1].begin(),s[1].end());//方便操作,直接把后半段翻转 s[0]=s[0].substr(0,n);//取前半段 dfs(1,0,0,0); dfs(1,0,0,1); cout<<ans; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端