【HDU5559 2015合肥赛区H】【观察找规律 构造】Frog and String 用最多k个字符构造长度为n的m不同回文串的串

24 篇文章 0 订阅
18 篇文章 0 订阅


Frog and String

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 61    Accepted Submission(s): 20
Special Judge


Problem Description
Frog studies algorithms on strings. He finds it so interesting that he can't stop playing with his strings. These days he has just learnt about palindrome, and comes up with a problem about it.

Given two integers,   N  and   M , he wants to construct a string of length   N , whose substrings contain exactly   M  distinct non-empty palindromes. A palindrome is a string which is exactly the same as the reverse of itself. For example, “ABBA”, “ADA”, “A”, and “UUSSUU” are palindromes, but “USTC”, “AB”, and “ABC” are not. A substring is a consecutive part of the original string. For example, “US”, “USTC”, “STC”, and “TC” are substrings of “USTC”, but “UC” and “CT” are not.

Frog finds it too hard for him to solve this problem. So he asks you for help. BTW, he won't make it too easy for you, so he decided to ask you solve this problem under his restrictions. You can only use the first   K  capital letters in the English alphabet   (AZ) . Please write a program to solve this problem.
 

Input
There is an integer   T  in the first line indicating the number of total test cases. ( T20000 ). Each test case contains three integers   N,M,  and   K , ( 1N,M100000,1K26 ), separated by single spaces. We guarantee the sum of   N  will not exceed 2000000.
 

Output
For each test case, output a single line consisting of “ Case #X:” first, where   X  is the test case number starting from 1. Output the string that you find in the next line. The string should contain only the first   K  capital letters. If there are multiple solutions, you can output any of them. If there is no such string satisfying Frog’s requirements, output “ Impossible” instead. Please follow the output format exactly, and do not output any additional character or new line.
 

Sample Input
      
      
4 3 3 3 4 4 4 2 2 1 2 1 1
 

Sample Output
      
      
Case #1: ABA Case #2: ABCD Case #3: AA Case #4: Impossible
Hint
For the first test case, “A”, “ABA”, “B” are the all distinct palindrome substrings of “ABA”. There are other possible answers, such as “BAB” and “AAA”. For the second test case, “USTC” is not a valid answer, because it contains letters other than the first 4 capital letters.
 

Source
 


#include<stdio.h> 
#include<iostream>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<string>
#include<algorithm>
#include<time.h>
#include<bitset>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T> inline void gmax(T &a,T b){if(b>a)a=b;}
template <class T> inline void gmin(T &a,T b){if(b<a)a=b;}
const int N=1e5+10,M=0,Z=1e9+7;
int casenum,casei;
int n,m,K;
char a[N];
//以下为爆搜打表程序
char b[4000];
bool flag;
map<string,int>mop;
void dfs(int p,int num)
{
    if(num>m)return;		//数量太多
	if(num+n-p<m)return;		//数量不够
    if(p==n)
    {
        flag=1;
        b[p]=0;
        puts(b);
        return;
    }
    for(int i=0;i<K;i++)
    {
        b[p]='A'+i;b[p+1]=0;
        for(int j=0;j<=p;j++)
        {
            int h=j;int t=p;
            while(h<t&&b[h]==b[t]){h++;t--;}
            if(h>=t&&++mop[b+j]==1)++num;
        }
        dfs(p+1,num);if(flag)return;b[p+1]=0;
        for(int j=0;j<=p;j++)
        {
            int h=j;int t=p;
            while(h<t&&b[h]==b[t]){h++;t--;}
            if(h>=t&&--mop[b+j]==0)--num;
        }
    }
}
void table()
{
    while(~scanf("%d%d%d",&n,&m,&K))
    {
        mop.clear();
        flag=0;
        dfs(0,0);
        if(!flag)puts("Impossible");
    }
}
//以下为构造程序
void solve()
{
    printf("Case #%d:\n",casei);
    if(n==m)
    {
        for(int i=0;i<n;i++)printf("%c",'A');
        puts("");
    }
	else if(n<m||K==1)
	{
		puts("Impossible");
	}
    else if(K==2)
    {
        if(n==8&&m==7)puts("AABABBAA");
        else if(m<8)puts("Impossible");
        else
        {
            a[0]='A';a[1]='A';a[2]='B';a[3]='A';a[4]='B';a[5]='B';
            int beh=m-8;
            int bef=n-beh;
            for(int i=6;i<bef;i++)a[i]=a[i%6];
            for(int i=bef;i<n;i++)a[i]=a[i-1];
            if(a[bef-1]!=a[bef-2])
            {
                int p=(bef-1)%6;
                if(p==0)
                {
                    a[bef++]='B';
                    a[bef++]='A';
                    a[bef++]='A';
                }
                else if(p==2)
                {
                    a[bef++]='B';
                }
                else if(p==3)
                {
                    a[bef++]='A';
                }
                else if(p==4)
                {
                    a[bef++]='A';
                    a[bef++]='A';
                }
            }
			for(int i=bef;i<n;i++)a[i]=a[i-1];a[n]=0;puts(a);
        }
    }
    else
	{
		if(m<3)puts("Impossible");
		else
		{
			int beh=m-3;
			int bef=n-beh;
			for(int i=0;i<bef;i++)a[i]='A'+i%3;
			for(int i=bef;i<n;i++)a[i]=a[i-1];a[n]=0;puts(a);
		}
	}
}
int main()
{
    //table();
    scanf("%d",&casenum);
    for(casei=1;casei<=casenum;casei++)
    {
        scanf("%d%d%d",&n,&m,&K);
        solve();
    }
}
/*
【trick&&吐槽】
1,对于构造的题目,其实可以一开始写个爆搜器。
	可以找规律,可以打补丁,可以对拍正确性,简直不能再舒服!
2,思维不要太浅,k==2的情况没有考虑清楚就写,导致wa了1次,查错2个小时QwQ

【题意】
T(20000)组数据,
每组数据给你n,m(1<=n,m<=1e5),k(1<=k<=26)。
让你构造一个长度恰好为n的串,串中只包含前k个大写字符,使得其包含恰好m个不相同的回文串。

【类型】
构造

【分析】
1,首先我们发现,如果n==m,以"AA...AA"的形式构造即可
2,然后我们发现,如果m>n,是不可能实现的。
	即:在一个长度为n个字符串中,本质不同回文串的数量不超过n。这个可以用一句话证明——
	以每个位置为结尾的回文串中,只有能延展出的最长回文串才是新的。
	因为——否则这个回文串一定是关于某个位置对称的,故而不是新的。位置只有n个,所以回文串最多也是n个。
3,于是,现在就只剩下m<n了。结合打表,便可以通过规律很快得到构造方法
(1)如果k==1,显然无解
(2)如果k==2,
	m<8的话无解,因为我们如果能出现重复回文串,也基于至少出现8个回文串的基础上。
	(然而有一点特殊,当n=8时m可以=7)
	这是因为对于:AABABB,这个串无限重复,形成AABABBAABABBAABABB……
	回文串也不过只有A,B,AA,BB,ABA,BAB,ABBA,BAAB八个。
	于是,在m>=8的时候,前面n-(m-8)个是AABABBAABABB……
	后面的m-8个回文串,要如何构造呢?
	我们重复的这个串AABABB,长度为6,于是分6个位置为结尾时的情况作讨论——
	pos1:(AABABB)A			:
		延展B,得到BABBAB;再延展A,得到ABABBABA;再延展A,得到AABABBABAA;后面一直延展A
	pos2:(AABABB)AA			:
		后面一直延展A
	pos3:(AABABB)AAB		:
		延展B,得到BBAABB;后面一直延展B
	pos4:(AABABB)AABA		:
		延展A,得到AABAA;后面一直延展A
	pos5:(AABABB)AABAB		:
		延展A,得到ABABA;再延展A,得到AABABAA;后面一直延展A
	pos6:(AABABB)AABABB		:
		后面一直延展B
(3)如果k==3,
	m<3的话无解,因为如果我们能出现重复回文串,也基于至少出现3个回文串的基础上。
	这是因为,我们发现ABCABCABC……这样的串,回文串的个数也只有3个,即'A','B','C',其它串长找不到对应。
	于是,在m>=3的时候,前面n-(m-3)个是ABCABCABC……,使得其最多只出现3个回文串,
	而之后的m-3个回文串,我们通过把最后一个字符一直扩增得到。

【时间复杂度&&优化】
O(n)

【数据】
input
8 7 2
output
AABABBAA

*/


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值