http://codevs.cn/problem/1185/
我们的模拟考,我靠;
钻石题,无题解;
我自然是没什么能耐,zzh大佬自然是秒了;
首先,我们达标找规律,发现一个结论;
n<=2000时答案个数不超过9个
在20以后就一定有解;
这个结论太好了;
然而其实也是对的;
至于证明,这个联系到关于博弈论的知识,我不是很会;
虽然我们知道最多只有9个数;
但是直接搜索9个数也是很难的;
因为一个数的范围太大了,我们要缩小;
那我们按位搜索
比如
一个数分解成
4+44+74+474
百位就是4
十位就是4+7+7
个位就是4+4+4+4
我们先1~9枚举会分解成几个数
我们再从n的最高位位开始枚举当前的位的数是什么(可以是0)
每位数最多9*7=63,我们可以方便理解为100;
如果枚举到0位,并且刚好n被分解,更新答案;
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Ll long long
using namespace std;
int e[20][120],q[100],x[12],y[12],d[12],w[12],v[12][12];
int n,ii,o;
void calc(){
memset(v,0,sizeof v);
for(int i=o;i;i--)
for(int k=0;k<=w[i];k++)
if(4*k+7*(w[i]-k)==d[i]){
for(int j=1;j<=w[i]-k;j++)v[i][j]=7;
for(int j=1;j<=k;j++)v[i][j+w[i]-k]=4;
break;
}
for(int i=ii;i;i--){
int k=0;
for(int j=o;j;j--)k=k*10+v[j][i];
y[ii-i+1]=k;
}
for(int i=1;i<=ii;i++)
if(y[i]<x[i]){
for(int i=1;i<=ii;i++)x[i]=y[i];
return;
}else if(y[i]>x[i])return;
}
bool dfs(int x,int y,int z,int now){//当前枚举到第x位,总共分成y个数,这一位值因为z,now自己看
if(!x)if(!z)return calc(),1;else return 0;
bool ans=0;
for(int i=now;i<=y;i++)
for(int j=1;j<=e[i][0];j++)
if((z>=e[i][j])&&(((z-e[i][j])*10+q[x-1])/7<=y)){
d[x]=e[i][j];w[x]=i;
ans=ans|dfs(x-1,y,((z-e[i][j])*10+q[x-1]),i);
}
return ans;
}
bool check(int x,int y){
for(int k=0;k<=y;k++)
if(4*k+7*(y-k)==x)return 1;
return 0;
}
int main()
{
freopen("lucky.in","r",stdin);
freopen("lucky.out","w",stdout);
e[0][0]=1;
for(int i=1;i<=100;i++)
for(int j=1;j<=12;j++)
if(check(i,j))
e[j][++e[j][0]]=i;//e表示用i个4或7可以组成的数
scanf("%d",&n);
if((n==1)||(n==2)||(n==3)||(n==5)||(n==6)||(n==9)||(n==10)||(n==13)||(n==17)){printf("No solution");return 0;}
for(;n;n/=10)q[++o]=n%10;
for(ii=1;ii<=12;ii++){//ii是全局变量
x[1]=1e9;
if(dfs(o,ii,q[o],0))break;
}
for(int i=1;i<=ii;i++)printf("%d ",x[i]);
}