HDU 3709 数位dp

HDU 3709(数位dp)

题意

求区间[L,R] 内满足以下性质的数:选定该数的一个位置,左右两边的力矩相等,如4139 ,选取'3'这位,左边 4×2+1×1 = 9×1.

思路

一开始想着枚举每个点来做,考虑正确性:对于同一个数,若它存在某个位置pos使得它满足性质,则将这个位置左移,则左值变小,右值变大,反之同理,必然不会导致重复

然后设计dp数组的状态,一开始直接设的暴力数组f[pos][point][lsum][rsum],每一边的数最大可以到 9×17×18/2 = 1377,肯定爆空间,考虑减少一个维度,发现左右值可以抵消,变成f[pos][point][val], val=rsum-lsum,为了避免出现负数,加一个偏移值key.

还有一个坑点,一开始弄暴力数组的时候发现暴力不对,然后打表输出数字发现,每次枚举的时候0都会算多一次,所以要在最后减去cnt-1次(cnt为数字位数)

代码

const int key=9*18*18;
int a[21],cnt;
int f[21][21][key*2+10];
//最多是最左或者最右端,9*18*18(9*18*17/2)
int dfs(int pos,int val,int point,int limit)
{
   if(!pos) return val==key;
   if(!limit&&f[pos][point][val]!=-1) return f[pos][point][val];
   int up=limit?a[pos]:9,sum=0;
   for(int i=0;i<=up;i++)
   {
   	sum+=dfs(pos-1,val+(pos-point)*i,point,limit&&(i==up));
   }
   if(!limit) f[pos][point][val]=sum;
   return sum;
}

int work(int x) 
{
   cnt=0;
   if(x<0) return 0;
   if(x==0) return 1;
   while(x) a[++cnt]=x%10,x/=10;
   int sum=0;
   for(int i=1;i<=cnt;i++)
   {
   	sum+=dfs(cnt,key,i,1);
   }
   sum-=max(0ll,cnt-1);
   return sum;
}
posted @ 2023-02-13 11:40  Liang2003  阅读(10)  评论(0编辑  收藏  举报