题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5334
题意:给出一个数字K,让我们输出一个字符串。这个字符串必须满足一个要求,那就是这个字符串的不同连续子串的数量和必须等于K;
解题思路:这题一看感觉怪怪的,其实也不是不能做。虽然,我一开始感觉怪怪的,但是不久之后,我变发现了规律。那就是:
在一个串中,有连续的2个相同子串,那么其不同连续子串的数量-1;比如:112345678的不同连续子串的数量为35,12345678的不同连续子串的数量36,正好差1
在一个串中,有连续的3个相同子串,那么其不同连续子串的数量-3;比如:111234567的不同连续子串的数量为33,12345678的不同连续子串的数量36,正好差3
在一个串中,有连续的4个相同子串,那么其不同连续子串的数量-6;比如:111123456的不同连续子串的数量为30,12345678的不同连续子串的数量36,正好差6
对于所有字符都不同的字符串来说(设其长度为m),其不同连续子串的数量=m*(m+1)/2;
所以,很显然,如果K=m*(m+1)/2,那么只要输出1 2 3 4.....m就可以了。但是,如果不想等呢?
那么,就是(m-1)*m/2<K<m*(m+1)/2之间,那么运用上述找出的规律就可以轻而易举的解题了。
下面举一些例子:
298
1 1 2 2 2 2 3 4
30
8
1 1 1 1 2 3 4 5
31
8
1 1 2 2 3 3 3 4
30
8
1 1 1 1 2 3 4 5
33
8
1 1 1 2 3 4 5 6
33
8
1 1 1 2 3 4 5 6
35
8
1 1 2 3 4 5 6 7
36
8
1 2 3 4 5 6 7 8
#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;
int main()
{
long long K;
while(~scanf("%I64d",&K))
{
if(K<100)
{
printf("%I64d\n",K);
printf("1");
for(int i=2;i<=K;i++)
{
printf(" 1");
}
printf("\n");
}
else
{
int m1,m2;
K=K*2;
long long a=1+4*K;
m1=(int)((sqrt(double(a))-1)/2);
if((m1*m1+m1==K))
{
printf("%d\n",m1);
printf("1");
for(int i=2;i<=m1;i++)
{
printf(" %d",i);
}
printf("\n");
}
else
{
int ans[100000+50];
m2=m1+1;
int ans1[4];
int tmp=m2*m2+m2-K;
tmp=tmp/2;
ans1[3]=tmp/6;
tmp=tmp-ans1[3]*6;
ans1[2]=tmp/3;
tmp=tmp-ans1[2]*3;
ans1[1]=tmp;
printf("%d\n",m2);
int num=1;
int pos=1;
for(int j=1;j<=3;j++)
{
for(int k=1;k<=ans1[j];k++)
{
if(j==1)
{
ans[pos++]=num;
ans[pos++]=num;
num++;
}
if(j==2)
{
ans[pos++]=num;
ans[pos++]=num;
ans[pos++]=num;
num++;
}
if(j==3)
{
ans[pos++]=num;
ans[pos++]=num;
ans[pos++]=num;
ans[pos++]=num;
num++;
}
}
}
for(int y=pos;y<=m2;y++)
{
ans[y]=num++;
}
printf("%d",ans[1]);
for(int x=2;x<=m2;x++)
{
printf(" %d",ans[x]);
}
printf("\n");
}
}
}
return 0;
}