1. 程式人生 > >custoj 233-很有趣的一道題

custoj 233-很有趣的一道題

描述

lzp喜歡搞笑數,所有搞笑的數都非常地搞笑,比如23333、233333、2333333。

所以說,一個搞笑數的每位上只能出現2或3

現給定一個正整數n,求一個搞笑數x,要求x是n的整數倍。

輸入

多組資料每行一個正整數n,n<=100000

輸出

對於每組資料,輸出一個搞笑數x,x的位數不能超過500若不存在這樣的搞笑數,輸出Unhappy

輸入樣例 1

4

輸出樣例 1

32

輸入樣例 2

6

輸出樣例 2

222222222222222222222222

來源

ccw630

剛看到這道題我是矇蔽的,請教了杭電的大佬才做出來。

主要還是運用了dp的思想 s[x][y]表示當該數除以n餘數為y時位數為x的解。比如不能整除2的個位數的一個解即為s[1][2]=2;顯然,一個合法的解就是s[x][0],x可以為任意數。然後如果當前s[x][y]有解(不為空時),可以得到s[x+1][(y+2)%n]="2"+s[x][y],換成3同理。用文字表示就是在解的前面加上一位2 相當於給餘數前面加上一位2然後對n取模(判斷整除或者超過),這就是核心思想了。我是萬萬想不到的。

除此以外,由於x位的資料只與x-1位的資料相關聯,所以可以採用滾動陣列,因為只要找一個就行,本身演算法就是從小到大判斷。

AC程式碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>

using namespace std;

const int maxn=100010;
string s[2][maxn];
int a[510];
string two="2",three="3";
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        if(n%5==0)
        {
            cout<<"Unhappy\n";
            continue;
        }
        a[1]=1%n;
        for(int i=2;i<501;i++)
            a[i]=a[i-1]*10%n;
        for(int i=0;i<n;i++)
            s[1][i]=s[0][i]="";
        s[1][2%n]="2",s[1][3%n]="3";
        if(s[1][0]!="")
            cout<<s[1][0]<<endl;
        else
        {
            int flag=0;
            for(int i=2;i<501;i++)
            {
                int t2=2*a[i]%n,t3=3*a[i]%n;
                for(int j=1;j<n;j++)
                {
                    if(s[(i+1)%2][j]!="")
                    {
                        s[i%2][(j+t2)%n]=two+s[(i+1)%2][j];
                        s[i%2][(j+t3)%n]=three+s[(i+1)%2][j];
                    }
                }
                for(int j=1;j<=n;j++)
                    s[(i+1)%2][j]="";
                if(s[i%2][0]!="")
                {
                    cout<<s[i%2][0]<<endl;
                    flag=1;
                    break;
                }
            }
            if(!flag)
                cout<<"Unhappy\n";
        }
    }
    return 0;
}