标签:小明 const 寿司 51Nod int V2 num getchar
传送门
题目
小明来到一家新开的日料店品尝回转寿司。
料理师傅共准备了26种不同的寿司,记为a~z。每次他都会选出每种寿司各一枚,按照一定顺序(如mildreabcfghjknopqstuvwxyz)放到传送带上,记为一轮。之后每轮,师傅都会按照同样的顺序将寿司放上传送带。
由于店内客人较多,寿司到达小明面前时已经所剩无几。小明记录了一段时间内经过自己面前的每一枚寿司的种类,现在他想知道,这期间至少有多少轮寿司经过了自己面前?
题解
比较摆烂,随便写写。
状压, 一开始每个字符单独一轮,考虑dp长度为20的那个字符串,加入第一个字母,假如是a,那么所有出现的a都可以把它后面的那个字母并入自己,同理,每加入一个字符,这个字符每次出现的位置,如果它后面的字符在原始字符串中也在它后面,那就并入;
预处理一个数组,\(pre_{a,b}\)表示a和b相邻,且a在b前面出现的次数。
这题大有可以研究的地方,诸如复用,无效信息等等,很神奇的是答案之和pre数组有关。
今日摆烂,下次一定
实现
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
int read(){
int num=0, flag=1; char c=getchar();
while(!isdigit(c) && c!='-') c=getchar();
if(c == '-') c=getchar(), flag=-1;
while(isdigit(c)) num=num*10+c-'0', c=getchar();
return num*flag;
}
const int N = 1e5+100;
const int Z = 2e6;
const int M = 21;
const int S = 26;
int vis[S], tab[S],cnt=0, s[N], n, pre[M][M];
vector<int> zt[M];
int f[Z];
void reads(){
char c=getchar();
while(c>='a' && c<='z') s[++n] = c-'a', c=getchar();
}
void dfs(int lzt, int x, int num){
if(x >= cnt){
zt[num].push_back(lzt);
return ;
}
dfs(lzt, x+1, num);
dfs(lzt+(1<<x), x+1, num+1);
}
int main(){
reads();
for(int i=1; i<=n; i++) vis[s[i]]=1;
for(int i=0; i<S; i++) if(vis[i]) tab[i]=cnt++;
for(int i=1; i<=n; i++) s[i] = tab[s[i]];
for(int i=1; i<n; i++) pre[s[i]][s[i+1]]++;
dfs(0, 0, 0);
for(int i=0; i<Z; i++) f[i]=n;
for(int i=1; i<=cnt; i++){
for(auto j : zt[i]){
for(int k=0; k<cnt; k++){
if(!(j & (1<<k)) ) continue;
int lzt = (j - (1<<k));
int res = 0;
for(int l=0; l<cnt; l++){
if(j & (1<<l)) continue;
res += pre[k][l];
}
f[j] = min(f[j], f[lzt]-res);
}
}
}
cout << f[zt[cnt][0]];
return 0;
}
标签:小明,const,寿司,51Nod,int,V2,num,getchar 来源: https://www.cnblogs.com/ltdjcoder/p/15941531.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。