bzoj3539【Usaco2014 Open】Odometer

3539: [Usaco2014 Open]Odometer

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 33   Solved: 24
[ Submit][ Status][ Discuss]

Description

 Farmer John's cows are on a road trip! The odometer on their car displays an integer mileage value, starting at X (100 <= X <= 10^18) miles at the beginning of their trip and ending at Y (X <= Y <= 10^18) miles at the end of their trip. Whenever the odometer displays an 'interesting' number (including at the start and end of the trip) the cows will moo. A number is 'interesting' if when you look at all its digits except for leading zeros, at least half of these should be the same. For example, the numbers 3223 and 110 are interesting, while the numbers 97791 and 123 are not. Help FJ count how many times the cows will moo during the trip. 

定义”有趣的数:把该数的前缀零去掉后,存在一个数字使得其出现次数至少为数位总数的一半,例如3223,110.
求[X,Y]中有多少个有趣的数”.

Input

* Line 1: The first line will contain two integers, X and Y, separated by a space. 

Output

 * Line 1: A single integer containing how many times the cows will moo during the trip. 

Sample Input

110 133

INPUT DETAILS: The trip starts with the odometer at 110 and ends at 133.

Sample Output

14
OUTPUT DETAILS: The cows moo when the odometer reads 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, 131, and 133.

HINT

Source




麻烦的DP题,不会做,抄代码。

dp[i][und][k][j],i表示位置,und表示i之前的位置是否小于上界,k为计数器(为了避免出现负数从25开始),j表示是否前面都为前导零。需要注意的是形如2233、454545这种只有两个数字且次数一样的会被计算两次,所以最后要减去。




#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define LL long long
#define MAXN 50
using namespace std;
string a,b;
LL dp[MAXN][2][MAXN][2];
LL getdp(string s,int l,int p1,int p2)
{
	memset(dp,0,sizeof(dp));
	dp[0][false][25][true]=1;
	F(i,0,l-1) F(und,0,1)
	{
		F(k,0,MAXN-1)
		{
			F(j,0,1)
			{
				LL cur=dp[i][und][k][j];
				F(nxt,0,9)
				{
					if (p2!=-1&&(nxt!=0||j==false)&&nxt!=p1&&nxt!=p2) continue;
					if (und==0&&nxt>s[i]-'0') continue;
					bool nj=j;
					nj&=!nxt;
					int nk=k;
					if (!nj)
					{
						if (p2!=-1)
						{
							if (nxt==p1) nk--;
							else if (nxt==p2) nk++;
						}
						if (p2==-1)
						{
							if (nxt==p1) nk--;
							else nk++;
						}
					}
					int nund=und;
					nund|=(nxt<s[i]-'0');
					dp[i+1][nund][nk][nj]+=cur;
				}
			}
		}
	}
	LL ret=0;
	if (p2!=-1)
	{
		F(i,0,1) ret+=dp[l][i][25][0];
		return ret;
	}
	F(i,0,1) F(k,0,25) ret+=dp[l][i][k][0];
	return ret;
}
LL f(string s)
{
	int l=s.size();
	LL ret=0,val;
	F(targ1,0,9)
	{
		val=getdp(s,l,targ1,-1);
		ret+=val;
	}
	F(targ1,0,9) F(targ2,targ1+1,9)
	{
		val=getdp(s,l,targ1,targ2);
		ret-=val;
	}
	return ret;
}
int main()
{
	cin>>a>>b;
	D(i,a.size()-1,0)
	{
		int c=a[i]-'0';
		if (c>0)
		{
			a[i]--;
			break;
		}
		else a[i]='9';
	}
	LL ans1=f(a),ans2=f(b);
	printf("%lld\n",ans2-ans1);
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值