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;
}
标签:HDU,val,point,int,18,pos,3709,dp
From: https://www.cnblogs.com/LIang2003/p/17115804.html