USACO2014Open Odometer

本文介绍了一种使用数位动态规划(DP)的方法来解决一个有趣的里程问题。问题中,若里程表显示的数字有一半以上的数字相同,牛群会发出叫声。任务是计算在给定区间内有多少个里程数会让牛群叫声。文章详细解释了解决方案,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Odometer

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.

PROBLEM NAME: odometer

INPUT FORMAT:

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

SAMPLE INPUT (file odometer.in):

110 133

INPUT DETAILS:

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

OUTPUT FORMAT:

Line 1: A single integer containing how many times the cows will mooduring the trip.

SAMPLE OUTPUT (file odometer.out):

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.

Task:如果一个数有至少一半的数字相同,那么FJ的牛就会moo~。给定100<=A,B<=1018,求区间[A,B]中的数字有多少个会使FJ的牛moo~。
Solution:
一道很不错的数位dp题。(其实是我不会做
我们可以将问题转化为calc(B)calc(A1)
定义dp[i][und][k][is0]i为当前要填的位数,und表示前面的位数是否已经是最大值(即当前位能否取到[0,9]中的所有数),k为一个计数器(相同数字的个数),is0即是前面有没有前导0。
转移的方式即是枚举当前位的数字的取值,转移到下一位。
于是calc(x)的求法就是显而易见的了:

  • 枚举超过一半次数的那个数字,将所有的可能加起来
  • 我们会发现有一种情况被算了两次:即时两种数字各占一半:如2626,9449等,我们需要减掉这些情况。
#include<stdio.h>
#include<string.h>
#include<iostream>
#define M 50
#define ll long long
using namespace std;
int sz,A[M];
ll dp[M][2][M+5][2];
void check(ll &a,ll b){
    if(a==-1)a=0;
    a+=b;
}
ll Dp(int t1,int t2){
    memset(dp,-1,sizeof(dp));
    dp[1][true][25][true]=1;//25为基数 
    for(int i=1;i<=sz;i++)
        for(int und=0;und<2;und++)
            for(int k=0;k<=M;k++)
                for(int is0=0;is0<2;is0++){
                    if(dp[i][und][k][is0]==-1)continue;
                    for(int nxt=0;nxt<=9;nxt++){
                        if(t2!=-1&&nxt!=t1&&nxt!=t2&&(!(nxt==0&&is0)))continue;//当前面是前导0时,当前填0可以忽略不计 
                        if(und&&nxt>A[i])break;//超过原数 
                        int nis0=is0&(nxt==0);
                        int nk=k;
                        if(!nis0){
                            if(t2==-1){
                                if(t1==nxt)nk--;
                                else nk++;
                            }else{
                                if(t1==nxt)nk--;
                                else if(nxt==t2)nk++;
                            }
                        }
                        int nund=und&(nxt>=A[i]);
                        check(dp[i+1][nund][nk][nis0],dp[i][und][k][is0]);
                    }
                }
    ll res=0;
    if(t2==-1){
        for(int i=0;i<2;i++)
            for(int k=0;k<=25;k++){
                ll rm=dp[sz+1][i][k][false];
                if(rm!=-1)res+=rm;
            }
    }else{
        for(int i=0;i<2;i++){
            ll rm=dp[sz+1][i][25][false];//两种数字的个数之差=0 
            if(rm!=-1)res+=rm;
        }
    }
    return res;     
}
ll calc(ll x){
    sz=0;
    ll b=1,res=0;
    if(x>=1e18)b=1e18;//无奈的防溢出... 
    else{
        while(x/b)b*=10;
        b/=10;
    }
    while(b){
        A[++sz]=x/b%10;
        b/=10;
    }
    for(int i=0;i<=9;i++)//计算 
        res+=Dp(i,-1); 
    for(int i=0;i<=9;i++)
        for(int j=i+1;j<=9;j++)//特殊情况 
            res-=Dp(i,j);
    return res;
}
int main(){
    ll a,b;
    cin>>a>>b;
    cout<<calc(b)-calc(a-1)<<endl;
    return 0;
}
Bill and Ted are taking a road trip. But the odometer in their car is broken, so they don't know how many miles they have driven. Fortunately, Bill has a working stopwatch, so they can record their speed and the total time they have driven. Unfortunately, their record keeping strategy is a little odd, so they need help computing the total distance driven. You are to write a program to do this computation. For example, if their log shows Speed in miles perhour Total elapsed time in hours 20 2 30 6 10 7 this means they drove 2 hours at 20 miles per hour, then 6-2=4 hours at 30 miles per hour, then 7-6=1 hour at 10 miles per hour. The distance driven is then (2)(20) + (4)(30) + (1)(10) = 40 + 120 + 10 = 170 miles. Note that the total elapsed time is always since the beginning of the trip, not since the previous entry in their log. Input The input consists of one or more data sets. Each set starts with a line containing an integer n, 1 <= n <= 10, followed by n pairs of values, one pair per line. The first value in a pair, s, is the speed in miles per hour and the second value, t, is the total elapsed time. Both s and t are integers, 1 <= s <= 90 and 1 <= t <= 12. The values for t are always in strictly increasing order. A value of -1 for n signals the end of the input. Output For each input set, print the distance driven, followed by a space, followed by the word "miles" Sample Input 3 20 2 30 6 10 7 2 60 1 30 5 4 15 1 25 2 30 3 10 5 -1 Sample Output 170 miles 180 miles 90 miles
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值