UVA 10712 - Count the Numbers 容斥

Problem H

Count the Numbers

Input: standard input
Output: standard output

Time Limit: 2 seconds

 

You're given three non-negative integers N (0 <= N <= 999)AB(0 <= A <= B <= 2000000000). Count the number of integers in the interval [A; B] which contain N as a subsequence.

For example if N = 3A = 3 and B = 17, there are two integers which contain N as a subsequence: 3 and 13.

 

Input

The input contains triples of numbers AB and N. The input ends with "-1 -1 -1". This line should not be processed.

 

Output

For each triple, output the answer on a new line.

 

Sample Input                              Output for Sample Input

3 17 3
0 20 0
0 150 17
-1 -1 -1

2
3
2

 


Author: Slavi Marinov
Translation and solution: Petko Minkov



思路:我用容斥做的....对N出现的位置进行容斥。 。。然后0 是特判的。


代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <string.h>
#include <cstring>
#include <map>
#include <stdio.h>
#include <cmath>
#include <cassert>
#include <math.h>
#define rep(i,a,b) for(int i=(a);i<(b);++i)
#define rrep(i,b,a) for(int i = (b); i >= (a); --i)
#define clr(a,x) memset(a,(x),sizeof(a))
#define LL long long
#define eps 1e-9
#define mp make_pair
using namespace std;
const int maxn = 30;
LL pw[maxn],dp[maxn],g[maxn];
int sum[maxn];
int n;
char S[maxn],T[maxn];
char d[maxn];
int len,nlen;

LL dfs(int cur,bool limit)
{
    if (cur == 0) return 1;
    if (!limit) return pw[sum[cur]];
    if (T[cur] != '?') {
        if (limit && T[cur] > d[cur]) return 0;
        return dfs(cur-1,limit && T[cur] == d[cur]);
    } else {
        int tail = limit ? d[cur] : 9;
        LL ans = 0;
        rep(v,0,tail+1)
            ans += dfs(cur-1,limit && v == tail);
        return ans;
    }
}

LL solve(LL x)
{
    if (x < 0) return 0;
    sprintf(d+1,"%lld",x);
    len = strlen(d+1);
    rep(i,1,maxn) d[i] -= '0';
    reverse(d+1,d+1+len);

    if (n == 0) {
        bool ok = false;
        LL ans = 0;
        rrep(i,len,1) {
            for(int v = 0; v < d[i]; ++v) {
                if ((i != len && v == 0) || ok) ans += pw[i-1];
                else if (i == len && v == 0) ans += g[i-1]+1;
                else ans += dp[i-1];
            }
            if (d[i] == 0) ok = true;
        }
        if (ok) ++ans;
        return ans;
    }
    int mask = (1<<(len-nlen+1));
    LL ans = 0;
    rep(s,1,mask) {
        rep(j,1,len+1) T[j] = '?';
        bool flag = true;
        int odd = 0;
        for(int j = 0; j < len-nlen+1 && flag; ++j) if (s & (1<<j)) {
            for(int k = 0; k < nlen && flag; ++k) {
                if (T[k+j+1] == '?') T[k+j+1] = S[k];
                else if (T[k+j+1] != S[k]) flag = false;
            }
            odd ^= 1;
        }
        reverse(T+1,T+1+len);
        if (!flag) continue;
        for(int j = 1; j <= len; ++j) {
            sum[j] = sum[j-1];
            if (T[j] == '?') sum[j]++;
        }
        if (odd) ans += dfs(len,true);
        else ans -= dfs(len,true);
    }
    return ans;
}

int main()
{
    #ifdef ACM
        freopen("in.txt", "r", stdin);
       // freopen("out.txt","w",stdout);
    #endif // ACM
    pw[0] = 1; rep(i,1,maxn) pw[i] = pw[i-1] * 10;

    dp[0] = 0;
    rep(i,1,maxn) {
        dp[i] = pw[i-1] + 9 * dp[i-1];
        g[i] = g[i-1] + dp[i-1] * 9;
    }
    LL A,B;
    while (scanf("%lld%lld%d",&A,&B,&n)==3) {
        if (n + A + B == -3) break;

        sprintf(S,"%d",n);
        nlen = strlen(S);
        rep(i,0,maxn) S[i] -= '0';


        LL ans = 0;
        ans += solve(B);
        ans -= solve(A-1);
        printf("%lld\n",ans);

    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值