Description

    众所周知,fang G 有很多小伙伴,有一天,Fang G 打算带他们去玩有趣的游戏OOXX,这个游戏需要分成两组,有趣的是,每个人互相之间都有一个满意度,大家都想和自己看重的人(excuse me???)一组,却又不希望和另一组拉开差距。
    Fang G
发现,每个队伍能发挥出的能力值和这个队伍之间满意值是相等的,而一个队伍之间满意值定义为每一个人对于这个队伍所有人(注意是所有人哦!!!)满意度总和的总和,而一个人对另外一个人的满意度和他们的名字是有关的,A对B的满意度定义为A名字前缀和B名字后缀的最长公共前缀(其实就是首x尾o相x连o辣)。
    而Fang G要做的就是如何分为两队,使得ooxx更加精彩!但是Fang G 现在有事情要做(是什么事情呢?),没办法完成分配工作,你现在就要帮他完成这个伟大的使命!使得两队在能力值差值最小的情况下,能力值较低的那一队满意度尽量高。

Input

第一行输入一个T代表测试数据的组数(T<=10)
接下来每组测试数据里:
第一行输入一个n代表待分队的人数(1<=n<=20)
接下来有n行,每行有一个字符串si代表每个人的姓名0<|si|<=10000

Output

对于每组测试数据,输出一行,从小到大输出两个数字分别代表两只队伍的能力值,两个数字之间用空格隔开

Sample Input

1
3
aab
bbc
cca

Sample Output

3 7

思路:KMP能求出互相之间的满意度。然后我们要遍历所有可能。遍历的复杂度O(2 ^ n),但是如果我们用n * n的复杂度去判断每一种情况每队的满意度会超时。我们可以用状压DP。显然一共1 << n种可能。我们从0开始往1 << n - 1判,最低位出现的1一定是新变化的,那么我就可以直接算出原来的情况+新增一个最低位的1,达到O(n)算出每队的满意度。

代码:

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = + ;
const ull seed = ;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + ;
char s[][maxn];
int w[][];
int Next[maxn], len[maxn];
int dp[ << ];
int n;
void preKMP(int pos){
int i = , j = -;
Next[] = -;
while(i < len[pos]){
while(j != - && s[pos][i] != s[pos][j]) j = Next[j];
++i;++j;
Next[i] = j;
}
}
int KMP(int p, int str){
int i = , j = ;
while(i < len[str]){
while(j != - && s[p][j] != s[str][i]) j = Next[j];
++j;
++i;
if(i == len[str]) return j;
if(j >= len[p]){
j = Next[j];
}
}
return ;
}
int dis, ans1, ans2;
int main(){
int t;
scanf("%d", &t);
while(t--){
scanf("%d" ,&n);
for(int i = ; i < n; i++){
scanf("%s", s[i]);
len[i] = strlen(s[i]);
}
for(int i = ; i < n; i++){
preKMP(i);
for(int j = ; j < n; j++){
if(j == i){
w[i][j] = len[i];
continue;
}
w[i][j] = KMP(i, j);
}
} memset(dp, , sizeof(dp));
int mx = ( << n) - ;
for(int i = ; i <= mx; i++){
for(int j = ; j < n; j++){
if(i & ( << j)){
for(int k = j + ; k < n; k++){
if(i & ( << k)){
dp[i] += w[j][k] + w[k][j];
}
}
dp[i] += dp[i - ( << j)] + w[j][j];
break;
}
}
}
dis = INF;
ans1 = -INF, ans2 = -INF;
for(int i = ; i <= mx; i++){
if(abs(dp[i] - dp[mx ^ i]) < dis){
dis = abs(dp[i] - dp[mx ^ i]);
ans1 = min(dp[i], dp[mx ^ i]);
ans2 = max(dp[i], dp[mx ^ i]);
}
else if(abs(dp[i] - dp[mx ^ i]) == dis){
int r1 = min(dp[i], dp[mx ^ i]);
int r2 = max(dp[i], dp[mx ^ i]);
if(r1 > ans1){
ans1 = r2, ans2 = r2;
}
}
}
printf("%d %d\n", ans1, ans2);
}
return ;
}

FJNU Fang G and his Friends(状压DP)题解的更多相关文章

  1. Codeforces Gym 100610 Problem K. Kitchen Robot 状压DP

    Problem K. Kitchen Robot Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/10061 ...

  2. POJ 3254 - Corn Fields - [状压DP水题]

    题目链接:http://poj.org/problem?id=3254 Time Limit: 2000MS Memory Limit: 65536K Description Farmer John ...

  3. BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3336  Solved: 1936[Submit][ ...

  4. ZOJ3802 Easy 2048 Again (状压DP)

    ZOJ Monthly, August 2014 E题 ZOJ月赛 2014年8月 E题 http://acm.zju.edu.cn/onlinejudge/showProblem.do?proble ...

  5. CF453B Little Pony and Harmony Chest (状压DP)

    CF453B CF454D Codeforces Round #259 (Div. 2) D Codeforces Round #259 (Div. 1) B D. Little Pony and H ...

  6. fzu2188 状压dp

    G - Simple String Problem Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & ...

  7. loj 1316(spfa预处理+状压dp)

    题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=27024 题意:求0-(n-1)的经过最多的标记的点的最短路. 思路 ...

  8. HDU5816 Hearthstone(状压DP)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5816 Description Hearthstone is an online collec ...

  9. HDU 4568 Hunter 最短路+状压DP

    题意:给一个n*m的格子,格子中有一些数,如果是正整数则为到此格子的花费,如果为-1表示此格子不可到,现在给k个宝藏的地点(k<=13),求一个人从边界外一点进入整个棋盘,然后拿走所有能拿走的宝 ...

随机推荐

  1. python基础2 数据类型、数据拼接、数据转换

    一.数据类型 1.字符串 字符串英文string,简写str,只要是被[单/双/三引号]这层皮括起来的内容,不论那个内容是中文.英文.数字甚至火星文.只要是被括起来的,就表示是字符串类型 如:prin ...

  2. 2018-2019-2 网络对抗技术 20165336 Exp1 PC平台逆向破解

    2018-2019-2 网络对抗技术 20165336 Exp1 PC平台逆向破解 1. 逆向及Bof基础实践说明 1.1 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件.该程序正常 ...

  3. Spark学习笔记11面向对象编程

    面向对象编程   11.1 object类 11.1.1定义一个简单的类   11.1.2 field的getter与setter 定义类包含,定义类的field及方法.其格式如下 class Cla ...

  4. 前端 CSS 注释

    /*开头 */ 结尾 /*这是注释*/ <!DOCTYPE html> <html lang="en"> <head> <meta cha ...

  5. 数据库设计入门及ERMaster的安装和使用

    数据库的设计步骤 1.标识表  (根据需求创建表) 2.标识表的字段 3.标识表与表之间的关系 注意事项: 三大范式: 1.确保标识的字段的原子性,字段的概念分的不能再分 2.确保字段与表有依赖的关系 ...

  6. Android使用https与服务器交互的正确姿势

    HTTPS 使用 SSL 在客户端和服务器之间进行加密通信,错误地使用 SSL ,将会导致其它人能够拦截网络上的应用数据. 使用一个包含公钥及与其匹配的私钥的证书配置服务器,作为 SSL 客户端与服务 ...

  7. SSH三大框架的工作原理以及流程

    Hibernate工作原理以及为什么要用 原理:1.通过Configuration().configure();读取并解析hibernate.cfg.xml配置文件2.由hibernate.cfg.x ...

  8. windows下安装php reids扩展

    1.使用phpinfo()函数查看PHP的版本信息,这会决定扩展文件版本. 2.下载php_igbinary-1.2.1-5.5-ts-vc11-x64.zip,php_redis-2.2.5-5.6 ...

  9. Linux给MySQL创建用户,并分配权限

    //登录MYSQL 使用root账号登录 @>mysql -u root -p @>密码 //创建用户 mysql> insert into mysql.user(Host,User ...

  10. package,继承,访问修饰符

    1.package 包(package),用于管理程序中的类,可用于处理类的同名问题. 1.1定义package的方法 package 包名; package用于定义包,必须写在源文件有效代码的第一句 ...