题目大意:
定义对于每一棵樱桃树有一个给定的编号,从这棵树上能够摘下的樱桃的数量为每段数字相同的连续区间的长度的平方乘上该段数值的和。例如编号为7774407的树,需要把它的编号分为777,44,0,7,每个区间的值分别为7*3^2,4*2^2,0*1^2,7*1^2,那么从这棵树上能摘下的樱桃树为63+16+0+7=86。现在给定一段区间[a,b],求在编号以a开头,以b结尾的这段区间内共能摘下多少樱桃。
输入:
共一行,两个数a,b(1<=a<=b<=10^15)
输出:
一个数,表示区间内一共能摘到的樱桃
分析:
考试的时候没有时间了,随便乱写了一个暴力,只得了20分,考完过后听评讲,知道了这是一个按位dp……根据每一位上的数字来动态规划……f[i][j][0]表示第i位为j的严格小于原数前i位的能够摘到樱桃数目,f[i][arr[i]][1]表示在第i位及之前与原数相同的数能够摘到的樱桃数,具体实现请参照代码。
Code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define MAXL 15
using namespace std;
LL a,b;
LL f[MAXL+5][10][2],g[MAXL+5][10][2];
int A[MAXL+5],B[MAXL+5];
int lena,lenb;
void gget(int arr[],int len)
{
int i,j,k;
g[0][0][0]=0;
g[0][0][1]=1;
for(i=1;i<=len;i++)
{
for(j=0;j<=9;j++)
{
for(k=0;k<=9;k++)
g[i][j][0]+=g[i-1][k][0];
if(j<arr[i])//这个if不在上一个循环中
g[i][j][0]+=g[i-1][arr[i-1]][1];
}
g[i][arr[i]][1]=1;
}
}
LL dp(int arr[],int len)
{
LL res=0;
int i,j,k,z;
memset(g,0,sizeof g);
memset(f,-1,sizeof f);
gget(arr,len);
f[0][0][0]=0;
f[0][0][1]=0;//记住初始化
for(i=1;i<=len;i++)
{
for(k=i-1;k>=0;k--)
{
for(j=0;j<=9;j++)
for(z=0;z<=9;z++)
if((z!=j||k==0)&&f[k][z][0]>=0)
{
if(f[i][j][0]==-1)
f[i][j][0]=0;
f[i][j][0]+=f[k][z][0]+j*(i-k)*(i-k)*g[k][z][0];//g[k][z][0]表示在第k个位置前有多少个能够满足在第k位及之前小于原数的个数
}
for(j=0;j<=arr[k+1];j++)
{
bool flag=false;
int ti=0;
if(j==arr[k+1])
{
flag=false;
for(ti=k+2;ti<=i;ti++)
{
if(j>arr[ti])
{
flag=true;
break;
}
else if(j<arr[ti])
{
flag=false;
break;
}
}
}
if(ti>i)
flag=true;
if(flag)
break;
if(f[k][arr[k]][1]>=0)//此时z的值无用
{
if(f[i][j][0]==-1)
f[i][j][0]=0;
if(j!=arr[k]||k==0)//有条件
f[i][j][0]+=f[k][arr[k]][1]+j*(i-k)*(i-k);
}
}
}
int tk;
for(tk=i-1;tk>0&&arr[i]==arr[tk];tk--);
f[i][arr[i]][1]=f[tk][arr[tk]][1]+arr[i]*(i-tk)*(i-tk);
}
for(i=0;i<=9;i++)
if(f[len][i][0]>0)
res+=f[len][i][0];
if(f[len][arr[len]][1]>0)
res+=f[len][arr[len]][1];
return res;
}
int main()
{
LL tmp;
int i;
scanf("%I64d%I64d",&a,&b);
tmp=a-1;
do{
A[++lena]=tmp%10;
tmp/=10;
}while(tmp);
for(i=1;i<=lena/2;i++)
swap(A[i],A[lena-i+1]);
tmp=b;
do{
B[++lenb]=tmp%10;
tmp/=10;
}while(tmp);
for(i=1;i<=lenb/2;i++)
swap(B[i],B[lenb-i+1]);
printf("%I64d\n",dp(B,lenb)-dp(A,lena));
}