zoukankan      html  css  js  c++  java
  • test20181016 B君的第一题

    题意

    题面
    数据范围

    分析

    考场爆零做法

    考虑位数少的一定更小,高位小的一定更少。

    然后计算一定位数下不同数字的个数,然后从高到低依次确定数位。

    特例:如果确定的高位的后缀出现了x,那么要把x调整到后缀去,这样一定更优。

    然而这样做有问题,有重复的情况,譬如样例1的6666。

    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<iostream>
    #include<string>
    #include<vector>
    #include<list>
    #include<deque>
    #include<stack>
    #include<queue>
    #include<map>
    #include<set>
    #include<bitset>
    #include<algorithm>
    #include<complex>
    #pragma GCC optimize ("O0")
    using namespace std;
    template<class T> inline T read(T&x)
    {
        T data=0;
    	int w=1;
        char ch=getchar();
        while(!isdigit(ch))
        {
    		if(ch=='-')
    			w=-1;
    		ch=getchar();
    	}
        while(isdigit(ch))
            data=10*data+ch-'0',ch=getchar();
        return x=data*w;
    }
    typedef long long ll;
    const int INF=0x7fffffff;
    
    const int MAXN=2e3+7;
    char X[MAXN],ans[MAXN];
    int len;
    ll n;
    
    int main()
    {
     freopen("python.in","r",stdin);
      freopen("python.out","w",stdout);
    	scanf("%s",X+1);
    	len=strlen(X+1);
    	read(n);
    	
    	if(n==1)
    	{
    		puts(X+1);
    		return 0;
    	}
    	n-=1;
    	
    	int lim;
    	for(lim=1;;++lim)
    	{
    		ll sum=(ll)lim*9*pow(10,lim-1)+pow(10,lim);
    		cerr<<"lim="<<lim<<" sum="<<sum<<endl;
    		if(n>sum)
    			n-=sum;
    		else
    			break;
    	}
    	cerr<<"n="<<n<<" lim="<<lim<<endl;
    	for(int i=1;i<=lim;++i)
    	{
    		cerr<<"i="<<i<<endl;
    		for(int j=(i==1?1:0);j<=9;++j)
    		{
    			ll sum=(ll)(lim-i+1)*pow(10,lim-i);
    //			cerr<<" j="<<j<<" sum="<<sum<<endl;
    			if(n>sum)
    				n-=sum;
    			else
    			{
    				ans[i]=j+'0';
    				ans[i+1]=0;
    				break;
    			}
    			if(j==9)
    				abort();
    		}
    		cerr<<"ansi="<<ans[i]<<endl;
    
    		if(i>=len&&strcmp(ans+i-len+1,X+1)==0)
    		{
    //			cerr<<"n="<<n<<endl;
    			int j;
    			for(j=lim+len;n;--j,n/=10)
    			{
    				ans[j]=n%10+'0';
    			}
    			for(;j>i;--j)
    			{
    				ans[j]='0';
    			}
    			puts(ans+1);
    			return 0;
    		}
    	}
    	printf("%s%s",ans+1,X+1);
    //  fclose(stdin);
    //  fclose(stdout);
        return 0;
    }
    

    标解

    毕姥爷太强了。

    匹配字符串,考虑自动机上dp。

    构造对x的KMP自动机,只是末尾位置的trans均指向末尾。

    那么如果数字中出现过x,自动机上跑出来一定在末尾位置。

    (f(i,j))表示从状态j走i步走到末尾位置上的方案数。写出转移方程:

    [f(i,j)=sum_{k=0}^{9}f(i-1, extrm{trans}(j,k)) ]

    边界条件(f(0, extrm{maxstate})=1)

    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<iostream>
    #include<string>
    #include<vector>
    #include<list>
    #include<deque>
    #include<stack>
    #include<queue>
    #include<map>
    #include<set>
    #include<bitset>
    #include<algorithm>
    #include<complex>
    #pragma GCC optimize ("O0")
    using namespace std;
    template<class T> inline T read(T&x)
    {
        T data=0;
    	int w=1;
        char ch=getchar();
        while(!isdigit(ch))
        {
    		if(ch=='-')
    			w=-1;
    		ch=getchar();
    	}
        while(isdigit(ch))
            data=10*data+ch-'0',ch=getchar();
        return x=data*w;
    }
    typedef long long ll;
    typedef unsigned long long ull;
    const ll INF=(1ULL << 63) - 1;
    
    const int MAXN=2e3+20;
    char s[MAXN];
    ll n;
    
    int nx[MAXN];
    int trans[MAXN][MAXN];
    
    ull f[MAXN][MAXN];
    
    
    int main()
    {
      freopen("python.in","r",stdin);
      freopen("python.out","w",stdout);
    	scanf("%s",s+1);
    	int l=strlen(s+1);
    	
    	// 处理next数组 
    	int p=0;
    	for(int i=2;i<=l;++i)
    	{
    		while(p && s[p+1] != s[i])
    		{
    			p = nx[p];
    		}
    		if(s[p+1] == s[i])
    		{
    			++p;
    		}
    		nx[i]=p;
    	}
    	
    	for(int i=0;i<l;++i) // 处理trans转移数组 
    		for(int j=0;j<10;++j)
    		{
    			p = i;
    			while(p && s[p + 1] != j + '0')
    			{
    				p = nx[p];
    			}
    			if(s[p + 1] == j + '0')
    			{
    				++p;
    			}
    			trans[i][j] = p;
    		}
    	for(int i=0;i<10;++i)
    	{
    		trans[l][i]=l;
    	}
    	
    	f[0][l]=1;
    	for(int i=1;i<2015;++i) // 2015是估计值 
    		for(int j=0;j<=l;++j)
    			for(int k=0;k<10;++k)
    			{
    				f[i][j] += f[i-1][trans[j][k]];
    				if(f[i][j] > INF)
    				{
    					f[i][j] = INF;
    				}
    			}
    	
    	read(n);
    	int lim;
    	for(lim=1;lim < 2015 && f[lim][0] < n;++lim); 
    	p=0;
    	for(int i=lim,j;i;--i)
    	{
    		for(j=0;j<10;++j)
    		{
    			if(n > f[i-1][trans[p][j]])
    				n -=  f[i-1][trans[p][j]];
    			else
    				break;
    		}
    		printf("%d",j);
    		p = trans[p][j];
    	}
    	puts("");
    //  fclose(stdin);
    //  fclose(stdout);
        return 0;
    }
    
    静渊以有谋,疏通而知事。
  • 相关阅读:
    读《少有人走的路》《第3选择》
    《谁说这辈子只能这样》の悟
    日本专利的下载方法
    08.29 JavaScript 全局对象 JSON对象
    08.28 JavaScript 边界 选择修饰符 模式单元 修饰符 正则的使用
    08.25 javascript 倒计时+正则表达式 定义 作用 定义正则表达式
    08.24 javascript 内置对象 function apply() * call() * bind() ECMA5新增
    08.23 javasript 随机数 定时函数 多次函数 单次定时 Array属性 方法 ECMA5 新增方法
    08.22 javaScript 原型的定义 原型链 获取原型 操作原型的属性 判断原型是自有的还是继承的 各种方法
    08.21 javaScript07 object 概念 创建对象 创建属性操作 方法遍历 原型
  • 原文地址:https://www.cnblogs.com/autoint/p/9799688.html
Copyright © 2011-2022 走看看