• SHUOJ 1771


    http://202.121.199.212/JudgeOnline/problem.php?id=1771

    夏季赛H题

    Description

    Input

    第一行含有一个正整数 T,表示有 T 组测试数据。
    每组数据只有一行,包含三个整数 L_i,R_i,m。
    约定
        T≤200;
        0≤L≤R≤10^18;
        |m|≤100。

    Output

    对于每组测试用例,输出:
    第一行:Case #: (# 要替换成对应的数字)。
    输出两个整数,用一个空格分割。分别为在 [L_i,R_i ] 区间,有多少个数奇偶和等于 m,以及这些数的和(对和取模100000007后输出)。

    Sample Input

    3 1 10 2 10 20 4 10 30 -1

    Sample Output

    Case 1: 1 2 Case 2: 0 0 Case 3: 2 33

    HINT

    [1,10] 之间奇偶和为2的是2;

    [10,20] 之间没有奇偶和为4的;

    [10,30] 之间奇偶和为 -1的有10 23。

    解题报告:

    邝神出的题,果然不好做..orz

    这道题用数位DP来做, 算是第一次写..比赛时挂了10次..还算是最后过了

    奇偶和的概念很简单, 就是所有数位上偶数的和减去奇数的和

    思路如下:

    首先将0~9, 0~99, 0~999, ...奇偶和为m的利用数位DP写出一个计算函数

    然后对于一个任意数n 将它分割为 1~9..9 等

    如 123 可以分为 1~99, 100~109, 110~119, 120, 121, 122, 123

    然后对各部分使用数位dp计算结果 其中数字个数比较好处理, 而数字的和比较难处理, 注意算数字和的时候要先求模(因为这个挂了N次)

    分解的计算个数为最多 18*10 次, 并不是一个大数字

    数位dp的状态也最大只有 18*(18*9) 种

    最后出答案的时候记住两个相减求模的时候会出现负数 要再+MOD 再求模

    分解的部分(solve函数)在比赛的时候写麻烦了, 后来参照了邝神的标程, 改成了简单一些的代码.

    代码如下

    #include <iostream>
    #include <sstream>
    #include <ios>
    #include <iomanip>
    #include <functional>
    #include <algorithm>
    #include <vector>
    #include <string>
    #include <list>
    #include <queue>
    #include <deque>
    #include <stack>
    #include <set>
    #include <map>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <climits>
    #include <cctype>
    using namespace std;
    #define INF 0x3FFFFFFF
    #define MP(X,Y) make_pair(X,Y)
    #define PB(X) push_back(X)
    #define REP(X,N) for(int X=0;X<N;X++)
    #define REP2(X,L,R) for(int X=L;X<=R;X++)
    #define DEP(X,R,L) for(int X=R;X>=L;X--)
    #define CLR(A,X) memset(A,X,sizeof(A));
    #define IT iterator
    typedef long long ll;
    typedef pair<ll,ll> PII;
    typedef vector<PII> VII;
    typedef vector<int> VI;
    #define X first
    #define Y second
    
    #define MOD 100000007
    
    int fsum(ll n)
    {
        ll r=0;
        do{
            ll t=n%10;
            r-=t*((t&1)*2-1);
            n/=10;
        }while(n);
        return r;
    }
    
    ll dp[20][2000];
    ll sum[20][2000];
    ll ten[19];
    
    PII dfs(int n, int m)
    {
        if(n<=0)
        {
            if(m==0) return MP(1,0);
            return MP(0,0);
        }
        ll &dd = dp[n][m+1000];
        ll &ds = sum[n][m+1000];
        if(dd!=-1) return MP(dd,ds);
        ll count=0, sum=0;
        REP2(i,0,9)
        {
            PII r=dfs(n-1,m-fsum(i));
            count+=r.X;
            sum+=((i*(ten[n]%MOD)%MOD*(r.X%MOD))%MOD+r.Y);
            sum%=MOD;
        }
        dd=count;
        ds=sum;
        return MP(count, sum);
    }
    
    PII solve(ll n, ll m)
    {
        if(n<0) return MP(0,0);
        ll count=0, sum=0;
        int x=0;
        n++;
    	do{
    		REP(i,n%10)
    		{
        		PII r=dfs(x, m-fsum(n-i-1));
        		count+=r.X;
    			sum+=(((n-i-1)*ten[x+1])%MOD)*(r.X%MOD)%MOD+r.Y;
    			sum%=MOD;
    		}
        	n/=10;
        	x++;
        }while(n);
        return MP(count, sum);
    }    
    
    int main()
    {
        ios::sync_with_stdio(false);
        REP(i,19)
        {
            ten[i]=i>1?ten[i-1]*10:1;
            ten[i]%=MOD;
        }
        ten[0]=0;
        CLR(dp,-1);
        int t,cs=1;
        ll l,r,m;
        cin>>t;
        while(t--)
        {
            cout<<"Case "<<cs++<<":"<<endl;
            cin>>l>>r>>m;
            PII a=solve(l-1,m);
            PII b=solve(r,m);
            cout<<b.X-a.X<<' '<<((b.Y-a.Y)%MOD+MOD)%MOD<<endl;
        }
        return 0;
    }
    
  • 相关阅读:
    继承和派生
    面向过程和面向对象 , 面向对象基础
    numpy模块、matplotlib模块、pandas模块
    包 ,模块(time、datetime、random、hashlib、typing、requests、re)
    os模块 sys模块 json/pickle 模块 logging模块
    python模块基础
    匿名函数 python内置方法(max/min/filter/map/sorted/reduce)面向过程编程
    最简单的注册美区Apple ID方法
    迭代器 生成器 函数递归
    ODBC连接时报错不可识别的数据库格式
  • 原文地址:https://www.cnblogs.com/curs0r/p/3835766.html
Copyright © 2020-2023  润新知