题目链接
题目大意
给定区间[a,b],求区间内平衡数的个数。所谓平衡数即有一位做平衡点,左右两边数字的力矩想等。
题目思路
显然除了0以外,所有的数最多只有一个平衡点
遍历每一位做为平衡点,进行搜索,sum保存数字乘以距离的和,若sum为0,则说明平衡。
但是sum可能为负数,所以加一个偏移量2000,当sum=2000则平衡。
注意0会被多算,要-cnt+1,还有记忆化的时候应该是
if(!limit&&dp[pos][sum][mid]!=-1){
return dp[pos][sum][mid];
}
不应该是
if(dp[pos][sum][mid][limit]!=-1){
return dp[pos][sum][mid][limit];
}
因为当limit=1时,是不可以重复利用的。当limit=0,那么后面的位数都是0-9则可以重复利用
代码
#include<map>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int change=2000;//偏移量
int t,cnt,dig[20];
ll dp[20][4000][20],ans;
ll dfs(int pos,int sum,int mid,bool limit){
if(pos==0){
return sum==2000;
}
if(!limit&&dp[pos][sum][mid]!=-1){
return dp[pos][sum][mid];
}
ll ans=0;
for(int i=0;i<=9;i++){
if(limit&&i>dig[pos]) break;
ans+=dfs(pos-1,sum+i*(pos-mid),mid,limit&&i==dig[pos]);
}
if(!limit){
dp[pos][sum][mid]=ans;
}
return ans;
}
ll work(ll x){
cnt=0,ans=0;
if(x==-1){//不然会 return 1
return 0;
}
while(x>0){
dig[++cnt]=x%10;
x=x/10;
}
for(int i=1;i<=cnt;i++){
ans+=dfs(cnt,2000,i,1);
}
return ans-cnt+1;
}
int main(){
memset(dp,-1,sizeof(dp));// !!!!!!!!!!!!!!!!
scanf("%d",&t);
while(t--){
ll a,b;
scanf("%lld %lld",&a,&b);
printf("%lld\n",work(b)-work(a-1));
}
return 0;
}