Fun Game

https://odzkskevi.qnssl.com/8d698323a1e07d605cdeea708ee8a01d?v=1508703139

【题解】

不难发现如果一个串的原串或反转串是另一个串的子串,那么这个串是没有用的

我们把他剔除出去

如果此时只有一个串,暴力枚举解检查即可(网上很多写法是KMP。。不是很明白,没仔细看他们代码

多个串则状压DP

dp[s][i][0/1]表示s串已经选了,最后一个串是i,i是正着/倒着的,最大重叠字母数

刷表法转移即可

如何处理圈?我们强行在第一个串的地方断开,按照第一个串的正着的方向为圈的传递方向即可,

最后的时候枚举最后一个串跟第一个串交一下算答案

 #include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b)) inline void swap(int &a, int &b)
{
long long tmp = a;a = b;b = tmp;
} inline void read(int& x)
{
x = ;char ch = getchar(), c = ch;
while(ch < '' || ch > '')c = ch, ch = getchar();
while(ch <= '' && ch >= '')x = x * + ch - '', ch = getchar();
} const int INF = 0x3f3f3f3f;
const int MAXN = ;
const int MAXNUM = ; int dp[( << MAXN) + ][MAXN + ][], die[MAXN][][MAXN][], n, ma, sum, len[MAXN], cnt[MAXN], tot, b[MAXN];
char s[MAXN][MAXNUM]; inline void init()
{
memset(dp, , sizeof(dp));
memset(die, , sizeof(die));
tot = ;
sum = ;
memset(b, , sizeof(b));
memset(len, , sizeof(len));
memset(cnt, , sizeof(cnt));
//check j是否包含在i中
for(register int i = ;i <= n;++i)
{
scanf("%s", s[i] + );
len[i] = strlen(s[i] + );
}
for(register int i = ;i <= n;++ i)
for(register int j = ;j <= n;++ j)
{
if(i == j || b[i] || b[j] || len[j] > len[i])continue;
//正着配
for(register int a = ;a <= len[i] - len[j] + ;++ a)
{
int tmp1 = a;
while(s[i][tmp1] == s[j][tmp1 - a + ] && tmp1 - a + <= len[j]) ++ tmp1;
if(tmp1 - a + > len[j]) b[j] = ;
}
//倒着配
for(register int a = len[i];a >= len[j];-- a)
{
int tmp1 = a, p = ;
while(s[i][tmp1] == s[j][p] && p <= len[j]) -- tmp1, ++ p;
if(p > len[j]) b[j] = ;
}
}
for(register int i = ;i <= n;++ i)
if(!b[i])
cnt[++ tot] = i, sum += len[i];
//j跟在i后面重叠部分大小
for(register int p = ;p <= tot;++ p)
for(register int q = ;q <= tot;++ q)
{
int i = cnt[p], j = cnt[q];
if(i == j)continue;
//0 0
for(register int a = ;a <= len[i];++ a)
{
int b = , tmp = a;
while(s[i][tmp] == s[j][b] && tmp <= len[i] && b <= len[j])++ tmp, ++ b;
if(tmp > len[i])
{
die[p][][q][] = len[i] - a + ;
break;
}
}
//0 1
for(register int a = ;a <= len[i];++ a)
{
int b = len[j], tmp = a;
while(s[i][tmp] == s[j][b] && tmp <= len[i] && b >= )++ tmp, -- b;
if(tmp > len[i])
{
die[p][][q][] = len[i] - a + ;
break;
}
}
//1 0
for(register int a = len[i];a >= ;-- a)
{
int b = , tmp = a;
while(s[i][tmp] == s[j][b] && tmp >= && b <= len[j])-- tmp, ++ b;
if(tmp < )
{
die[p][][q][] = a;
break;
}
}
//1 1
for(register int a = len[i];a >= ;-- a)
{
int b = len[j], tmp = a;
while(s[i][tmp] == s[j][b] && tmp >= && b >= )-- tmp, -- b;
if(tmp < )
{
die[p][][q][] = a;
break;
}
}
}
ma = << tot;
} int main()
{
while(scanf("%d", &n) != EOF && n)
{
init();
int flag = ;
if(tot == )
{
int x = cnt[tot];
for(register int i = ;i <= len[x];++ i)
{
for(register int j = ;j <= len[x];++ j)
{
if(j + i - > len[x]) break;
int p1 = , p2 = j, rank = ;
while(s[x][p1] == s[x][p2] && rank < len[x])
{
++ p1, ++ p2, ++ rank;
if(p1 > len[x]) p1 = ;
if(p2 > j + i - ) p2 = ;
}
if(rank >= len[x])
{
printf("%d\n", max(, i));
flag = ;
break;
}
}
if(flag) break;
}
if(flag) continue;
}
//dp[S][i][0/1]表示以1号字符串为头,已经选了S,最后一个是i的正/反状态的最大折叠数
//dp[S | k][k][p] = max(dp[S | k][k][p], dp[S][i][p'] + die[i][p'][k][p])
for(register int S = ;S < ma;++ S)
for(register int i = ;i <= tot;++ i)/*分别用dp[S][i][0]和dp[S][i][1]去更新*/
{
if(!(S & ))continue;
if(!(S & ( << (i - )))) continue;
for(register int k = ;k <= tot;++ k)
{
if(S & ( << (k - ))) continue;
if(S == )
{
dp[S | ( << (k - ))][k][] = max(dp[S | ( << (k - ))][k][], dp[S][i][] + die[i][][k][]);
dp[S | ( << (k - ))][k][] = max(dp[S | ( << (k - ))][k][], dp[S][i][] + die[i][][k][]);
}
else
{
dp[S | ( << (k - ))][k][] = max(dp[S | ( << (k - ))][k][], max(dp[S][i][] + die[i][][k][], dp[S][i][] + die[i][][k][]));
dp[S | ( << (k - ))][k][] = max(dp[S | ( << (k - ))][k][], max(dp[S][i][] + die[i][][k][], dp[S][i][] + die[i][][k][]));
}
}
}
int ans = ;
for(register int i = ;i <= tot;++i)
ans = max(ans, max(dp[ma - ][i][] + die[i][][][], dp[ma - ][i][] + die[i][][][]));
printf("%d\n", max(, sum - ans));
}
return ;
}

UVA1204

UVA1204 Fun Game的更多相关文章

随机推荐

  1. 用maven创建Spring MVC项目

    用maven创建Spring MVC项目 mvn archetype:generate -DgroupId=fry-arthur -DartifactId=spring-mvc-study -Darc ...

  2. phpCOW机制详解

    写时复制(Copy-on-Write,也缩写为COW),顾名思义,就是在写入时才真正复制一份内存进行修改. COW最早应用在*nix系统中对线程与内存使用的优化,后面广泛的被使用在各种编程语言中,如C ...

  3. 学而有道--思维导图式总结(一):Nosql分类

    前言: 众所周知,学习是需要方法的.作为一名java程序员,我们需要学习无数的技能,然而我们的大脑并不买账,学习了一项知识,时间一久就会遗忘, 如何更好高效的回忆起曾经学习过的知识,是极其重要的. 有 ...

  4. java基础之Random类

    Random类 Random类中实现的随机算法是伪随机,也就是有规则的随机.在进行随机时,随机算法的起源数字称为种子数(seed), 在种子数的基础上进行一定的变换,从而产生需要的随机数字. 相同种子 ...

  5. Leetcode938. Range Sum of BST二叉搜索树的范围和

    给定二叉搜索树的根结点 root,返回 L 和 R(含)之间的所有结点的值的和. 二叉搜索树保证具有唯一的值. 示例 1: 输入:root = [10,5,15,3,7,null,18], L = 7 ...

  6. C/C++ 信号量 CreateSemaphore 用法

    HANDLE CreateSemaphore( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // SD LONG lInitialCount, // in ...

  7. python使用suds来调用webservice

    对于python仅作为客户端调用webservice的情况,推荐使用suds库来完成,比起zsi,soapy之类,它可以说是相当轻量级,使用非常方便. 安装suds建议使用easy_insall来做. ...

  8. python3 新特性

    1.格式化字符串f-string user = "Mike" log_message = f'User{user} has logged in' 2.路径管理库Pathlib 3. ...

  9. python 日记 day4

    1.为何数据要分类 数据是用来表示状态的,不同的状态应该用不同类型的数据来表示. 2.数据类型 数字 字符串 列表 元组 字典 集合 列表:列表相比于字符串,不仅可以储存不同的数据类型,而且可以储存大 ...

  10. SignalR 2.0 入门与提高 转载https://www.cnblogs.com/vance/p/SignalR.html

    SignalR 2.0 最近整理了SignalR2.0 部分知识点,原文翻译,由于自己是土鳖,翻译得不好的地方,欢迎指正!仅供各位初学者学习! 第一节. 入门ASP.NET SignalR2.0 1. ...