hdoj5334

题目链接: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之间,那么运用上述找出的规律就可以轻而易举的解题了。

下面举一些例子:

29
8
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;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值