[数位DP]JZOJ 4239 光棍

Description

快要到七夕了,又到了交(nue)往(gou)的季节。
恶梦坐在教室里,作为一个纯屌丝的他当然不会关心要送什么礼物给女生,然而他的前桌yves却在忙碌着各种各样的的短信。
恶梦注意到yves发短信给的电话号码似乎都满足着特别的性质,难道yves的"好朋友"是满足正态分布的?
由于yves有着自己最喜欢的数字a,2 <= a <= 9
恶梦从这里入手,发现了一些端倪。
假设yves发的电话号码是一个十进制数字S
恶梦发现S会满足以下三个性质中的一个
1. S是a的倍数。
2. S在十进制表示下的各项数字加起来是a的倍数。
3. S的某一位是a
比如说当a = 7时,21,16,17这三个数字都是会被yves发短信的,他们分别满足1,2,3性质。
恶梦很担心所有的女同学都被yves抢走了,但他一下子又数不过来那些同学没有被yves抢走,所以他把这个问题交给了你。
他会给你两个自然数L,R,以及yves最喜欢的数字a,
他并不希望你告诉他在[L,R]中有多少个同学没有被抢走,而希望你告诉他这些数字的平方和。
比如说3,7是合法的,那么你应该输出3^2 + 7^2 = 58这个数。
当然,由于答案可能很大,你只需要将答案对10^9 + 7取模即可。

Input

输入的第一行包括一个正整数T,表示总共有T组询问。
接下来有T行,每行三个整数L,R,A。

Output

输出包括T行,每行一个整数,表示对10^9 + 7取模的答案。

Sample Input

32 20 63 203 711 771 2

Sample Output

1884159326932817226

Data Constraint

对于15%的数据,0 <= L <= R <= 10^6,T = 1
对于35%的数据,0 <= L <= R <= 10^7,T = 1
另外有25%的数据,A = 2,L = 10^k,R = 10^v,k和v都是自然数。
对于100%的数据,0 <= L <= R <= 10^18,2 <= A <= 9, T <= 100

分析

因为答案显然可以ans[r]-ans[l-1],所以我们只考虑r

设f[i][same][mod][sum]为当前数的前i位与r的前i位相同,当前处理位与r的当前位是否相同(same),当前数对a的模为mod,当前数位的和对a的模为sum时的数字个数

然后转移边界就是当前位数字不能为a,当前位数字不能大于r的当前位

s,g分别为总和和平方和,平方和可以简单地用(x1+1)^2+(x2+1)^2+(x3+1)^2=x1^2+x2^2+x3^2+2*1*(x1+x2+x3)+3*1*1计算

最后答案为f[1][same][mod][sum]的总和,其中mod,sum!=0

#include <iostream>
#include <cstdio>
#include <memory.h>
using namespace std;
typedef long long ll;
const ll P=1e9+7;
int t,a;
ll l,r;
int c[20],cnt;
ll f[3][20][2][10][10];

ll Calc(ll x) {
    memset(f,0,sizeof f);cnt=0;
    while (x) c[++cnt]=x%10ll,x/=10ll;
    f[0][cnt+1][1][0][0]=1;
    for (int i=cnt;i;i--)
        for (int same=0;same<2;same++)
            for (int mo=0;mo<a;mo++)
                for (int sum=0;sum<a;sum++)
                    if (f[0][i+1][same][mo][sum])
                        for (int ch=0;ch<10;ch++)
                            if (ch!=a&&(same&&ch<=c[i]||!same)) {
                                bool same1=same&&c[i]==ch;
                                int mo1=(mo*10+ch)%a,sum1=(sum+ch)%a;
                                (f[0][i][same1][mo1][sum1]+=f[0][i+1][same][mo][sum])%=P;
                                (f[1][i][same1][mo1][sum1]+=f[1][i+1][same][mo][sum]*10ll%P+f[0][i+1][same][mo][sum]*ch)%=P;
                                (f[2][i][same1][mo1][sum1]+=f[2][i+1][same][mo][sum]*100ll%P+f[1][i+1][same][mo][sum]*ch*20ll%P+ch*ch*f[0][i+1][same][mo][sum]%P)%=P;
                            }
    ll ans=0;
    for (int same=0;same<2;same++)
        for (int mo=1;mo<a;mo++)
            for (int sum=1;sum<a;sum++)
                (ans+=f[2][1][same][mo][sum])%=P;
    return ans;
}

int main() {
    for (scanf("%d",&t);t;t--) {
        scanf("%lld%lld%d",&l,&r,&a);
        printf("%lld\n",(Calc(r)-Calc(l-1)+P)%P);
    }
}

原文地址:https://www.cnblogs.com/mastervan/p/10335995.html

时间: 2024-10-05 16:15:57

[数位DP]JZOJ 4239 光棍的相关文章

51Nod 1009 数字1的个数 | 数位DP

题意: 小于等于n的所有数中1的出现次数 分析: 数位DP 预处理dp[i][j]存 从1~以j开头的i位数中有几个1,那么转移方程为: if(j == 1) dp[i][j] = dp[i-1][9]*2+pow(10,i-1);else dp[i][j] = dp[i-1][9]+dp[i][j-1]; 然后注意下对于每个询问统计的时候如果当前位为1需要额外加上他后面所有位数的个数,就是n%pow(10,i-1); 这样总复杂度log(n)*10 #include <bits/stdc++.

HDU 3555 Bomb (数位DP)

数位dp,主要用来解决统计满足某类特殊关系或有某些特点的区间内的数的个数,它是按位来进行计数统计的,可以保存子状态,速度较快.数位dp做多了后,套路基本上都差不多,关键把要保存的状态给抽象出来,保存下来. 简介: 顾名思义,所谓的数位DP就是按照数字的个,十,百,千--位数进行的DP.数位DP的题目有着非常明显的性质: 询问[l,r]的区间内,有多少的数字满足某个性质 做法根据前缀和的思想,求出[0,l-1]和[0,r]中满足性质的数的个数,然后相减即可. 算法核心: 关于数位DP,貌似写法还是

51nod1043(数位dp)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1043 题意:中文题诶- 思路:数位dp 我们用dp[i][j]来存储长度为2*i且一半和为j的所有情况(包括前导0的情况),为了方便我们现在只讨论其一半的和的情况,因为如果包括前导0的话其两边的情况是一样的: 我们假设再长度为i-1的数字最前面加1位数字k,0<=k<=9(这位数字加在哪里并不影响答案,因为我们在计算i-1长度的时候已经计算了所有组合情况,

数位dp

1.[hdu3709]Balanced Number 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<cstdlib> 6 #include<algorithm> 7 #include<ctime> 8 #include<cmath> 9 #include<queue>

【HDU 3652】 B-number (数位DP)

B-number Problem Description A wqb-number, or B-number for short, is a non-negative integer whose decimal form contains the sub- string "13" and can be divided by 13. For example, 130 and 2613 are wqb-numbers, but 143 and 2639 are not. Your task

hdu 5898 odd-even number 数位DP

odd-even number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 716    Accepted Submission(s): 385 Problem Description For a number,if the length of continuous odd digits is even and the length

LightOJ1068 Investigation(数位DP)

这题要求区间有多少个模K且各位数之和模K都等于0的数字. 注意到[1,231]这些数最大的各位数之和不会超过90左右,而如果K大于90那么模K的结果肯定不是0,因此K大于90就没有解. 考虑到数据规模,数据组数,这题状态这么表示: dp[i][j][k]:位数为i模K结果为j且各位数之和模K结果为k的数字个数 然后就是转移方程,最后就是统计.. 统计部分好棘手...半乱搞下AC的..还是对数位DP的这一部分太不熟悉了. 1 #include<cstdio> 2 #include<cstr

HDU 4734 F(x)(数位DP)

Description For a decimal number x with n digits (A nA n-1A n-2 ... A 2A 1), we define its weight as F(x) = A n * 2 n-1 + A n-1 * 2 n-2 + ... + A 2 * 2 + A1 * 1. Now you are given two numbers A and B, please calculate how many numbers are there betwe

hdu 4734 数位dp

http://acm.hdu.edu.cn/showproblem.php?pid=4734 Problem Description For a decimal number x with n digits (AnAn-1An-2 ... A2A1), we define its weight as F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1. Now you are given two numbers A and B, plea