您的位置:首页 > 其它

FZU 1896

2010-04-27 12:27 225 查看
题目链接:http://acm.fzu.edu.cn/problem.php?pid=1896

题意:中文题就不用讲题意了的。

思路:比赛的时候,一直困惑如何去限制在区间内,大于左边界,小于右边界的去做,一直想不通。但总觉得是个陈题,弱弱的始终想不来的。

然后HS提示了一句,可以求1.。左边界,然后1.。。右边界。。一句惊醒梦中人。

dp[i][j][0] 表示前i位第i位为j的时候等于当前数所得到的个数。

dp[i][j][1] 表示前i位第i位为j的时候小于当前数所得到的个数。

其中j 为10表示有前i为都为0,与0区别开。我挂这个地方挂了很久。囧。。。

转移方程:dp[i][10][1] = dp[i-1][10][1] ;

dp[i][j][1] +=dp[i-1][10][1];(k==10&&j!=0)

dp[i][j][0] +=dp[i-1][k][0](k!=10 && abs(j-k)>=m &&j==s[i]-'0')

dp[i][j][1] +=dp[i-1][k][1](k!=10 && abs(j-k)>=m )

dp[i][j][1] +=dp[i-1][k][0](k!=10 && j<s[i]-'0' && abs(j-k)>=m)

代码:
]#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int dp[20][20][2];
char a[20] ,b[20];
int m ;
long long res(char s[] ){
long long resa  ;
int len ;
memset(dp,0,sizeof(dp));
dp[0][10][1] = dp[0][s[0]-'0'][0]  = 1 ;
len = strlen(s);
for(int i = 1 ; i < s[0]-'0';++i)dp[0][i][1] = 1 ;
for(int i = 1 ; i <len;++i){
dp[i][10][1] = dp[i-1][10][1] ;
for(int j = 0 ; j<10 ;++j )
for(int k = 0 ; k <= 10 ;++k ){
if(k==10&&j!=0)
dp[i][j][1] +=dp[i-1][10][1];
else if( k !=10){
if(abs(j-k)>=m &&j==s[i]-'0')
dp[i][j][0] +=dp[i-1][k][0];
if(abs(j-k)>=m )
dp[i][j][1] +=dp[i-1][k][1];
if(j<s[i]-'0' && abs(j-k)>=m)
dp[i][j][1] +=dp[i-1][k][0];
}
}
}
resa = 0 ;
for(int i = 0 ; i < 10 ;++i)resa+=dp[len-1][i][1];
return resa ;
}
int main(){
int t ,i;
long long resa , resb ;
scanf("%d",&t);
while(t--){
scanf(" %s %s%d",a,b,&m);
resa = res(a);resb = res(b);
int len = strlen(b);
for(i = 1 ; i <len;++i)if(abs(b[i]-b[i-1] ) < m)break;
if(i >=len)resb++;
cout<<resb-resa<<endl;
}
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: