Codeforces 38F-Smart Boy

本文介绍了一款名为SmartBoy的文字游戏,玩家需轮流构建字符串并确保其为词典中的子串。文章详细解析了游戏规则及评分标准,并通过记忆化搜索实现最优策略选择,最终确定胜者及其得分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Smart Boy
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Once Petya and Vasya invented a new game and called it "Smart Boy". They located a certain set of words — the dictionary — for the game. It is admissible for the dictionary to contain similar words.

The rules of the game are as follows: first the first player chooses any letter (a word as long as 1) from any word from the dictionary and writes it down on a piece of paper. The second player adds some other letter to this one's initial or final position, thus making a word as long as 2, then it's the first player's turn again, he adds a letter in the beginning or in the end thus making a word as long as 3 and so on. But the player mustn't break one condition: the newly created word must be a substring of a word from a dictionary. The player who can't add a letter to the current word without breaking the condition loses.

Also if by the end of a turn a certain string s is written on paper, then the player, whose turn it just has been, gets a number of points according to the formula:

where

  •  is a sequence number of symbol c in Latin alphabet, numbered starting from 1. For example, , and .
  •  is the number of words from the dictionary where the line s occurs as a substring at least once.

Your task is to learn who will win the game and what the final score will be. Every player plays optimally and most of all tries to win, then — to maximize the number of his points, then — to minimize the number of the points of the opponent.

Input

The first input line contains an integer n which is the number of words in the located dictionary (1 ≤ n ≤ 30). The n lines contain the words from the dictionary — one word is written on one line. Those lines are nonempty, consisting of Latin lower-case characters no longer than 30 characters. Equal words can be in the list of words.

Output

On the first output line print a line "First" or "Second" which means who will win the game. On the second line output the number of points of the first player and the number of points of the second player after the game ends. Separate the numbers by a single space.

Examples
input
Copy
2
aba
abac
output
Second
29 35
input
Copy
3
artem
nik
max
output
First
2403 1882


题意:有n个只由小写字母组成的字符串,两个人轮流从一个空字符串开始构造字符串,要求每个人在其操作轮要加一个字符在已有字符串前面或者后面使得这个字符串依旧是这n个字符串中某些字符串的子串,如果没有合法方案则该人失败,否则该人得分,假设该人操作后字符串为s,则本轮得分Score(s)=(∑i=1|s|value(si))∗max1≤i≤|s|{|value(si)}+num(s),其中value(c)为c在26个字母中的位置,即value(′a′)=1,value(′z′)=26num(s)为这n个字符串中以s为子串的字符串数量,每个人在操作时采取最优策略让自己赢,且在保证自己赢的情况下使得自己得分最高,在保证自己赢且得分最高的情况下使得对方得分尽可能少,问最后哪一个人赢以及两个人的得分

解题思路:由于字符串数量和长度都不超过30,不同子串数不多,预处理出每个子串的num,之后对所有可能的情况记忆化搜索即可


#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <string>  
#include <algorithm>  
#include <map>  
#include <set>
#include <stack>  
#include <queue>  
#include <vector>  
#include <bitset>  
#include <functional>  

using namespace std;

#define LL long long
const int INF = 0x3f3f3f3f;

struct node
{
	int sg, sum1, sum2;
	bool operator < (const node &x)const
	{
		if (sg != x.sg) return sg < x.sg;
		if (sum1 != x.sum1) return sum1 < x.sum1;
		return sum2 > x.sum2;
	}
};

set<string>S;
map<string, node>mp;
map<string, int>num;

int get(string s)
{
	int ans = 0, mx = 0, len = s.length();
	for (int i = 0; i < len; i++)
	{
		ans += s[i] - 'a' + 1;
		mx = max(mx, s[i] - 'a' + 1);
	}
	return ans * mx + num[s];
}

node dfs(string s)
{
	if (mp.find(s) != mp.end()) return mp[s];
	node ans = { 0, 0, 0 };
	for (int i = 0; i < 26; i++)
	{
		string ss = s + char('a' + i);
		if (S.find(ss) != S.end())
		{
			node tmp = dfs(ss);
			swap(tmp.sum1, tmp.sum2);
			tmp.sg ^= 1;
			tmp.sum1 += get(ss);
			if (ans < tmp) ans = tmp;
		}
		ss = char('a' + i) + s;
		if (S.find(ss) != S.end())
		{
			node tmp = dfs(ss);
			swap(tmp.sum1, tmp.sum2);
			tmp.sg ^= 1;
			tmp.sum1 += get(ss);
			if (ans < tmp) ans = tmp;
		}
	}
	return mp[s] = ans;
}

int main()
{
	int n, len;
	string s, ss;
	while (~scanf("%d", &n))
	{
		for (int i = 1; i <= n; i++)
		{
			cin >> s;
			set<string>tmp;
			len = s.length();
			for (int j = 0; j < len; j++)
			{
				for (int k = j; k < len; k++)
				{
					ss = s.substr(j, k - j + 1);
					S.insert(ss);
					if (tmp.find(ss) == tmp.end())
					{
						tmp.insert(ss);
						num[ss]++;
					}
				}
			}
		}
		node ans = dfs("");
		if (ans.sg) printf("First\n");
		else printf("Second\n");
		printf("%d %d\n", ans.sum1, ans.sum2);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值