zoukankan      html  css  js  c++  java
  • [HDU4507]恨7不成妻(数位dp)

    题意

    给定区间[ l , r ]((1 leq l < r leq 1e18)),求在区间中满足下列条件的所有数x的平方和:

    不存在数字7;不是7的倍数;每一位的数字的和也不是7的倍数

    思路

    数位dp

    状态:位置i,数对7取模j,各个位的和对7取模(,是否顶上界)

    下面的代码用记忆化搜索方式实现,从低位向高位递进。

    已知后面i位数满足的平方和,再在前面加入一个数怎么办

    维护后面i位的平方和pow,由((a+i)^2)=(a^2+2ai+i^2),已知(i^2),那么再加上(a^2+2ai)即可,由于要用到'i',所以还要维护后面i位的和sum。另外,由于后i位可能有很多满足条件的数,所以还要维护个数cnt

    转移有很多细节,比之前写的睿(ruo)智数位dp确实难了一些

    Code:

    #include<bits/stdc++.h>
    #define N 25
    using namespace std;
    typedef long long ll;
    const ll mod = 1000000007;
    int T,a[N],sum;
    ll n,m,x,temp[N];
    struct Node
    {
    	ll cnt,sum,po;
    	Node() {cnt=-1;sum=po=0;}
    	Node(ll c,ll s,ll p) : cnt(c),sum(s),po(p) {}
    }f[N][8][8];//无限制lim才能用的记忆化 
    template <class T>
    void read(T &x)
    {
    	char c;int sign=1;
    	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    	while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
    }
    Node dfs(int pos,int wei,int sum,int lim)//在pos填数,位数和,数,顶上界 
    {
    	if(!pos) return wei==0||sum==0 ? Node(0,0,0):Node(1,0,0);
    	if(f[pos][wei][sum].cnt!=-1&&!lim) return f[pos][wei][sum];
    	int mx=lim ? a[pos] : 9;
    	Node now=Node(0,0,0);
    	for(int i=0;i<=mx;++i)//注意细节
    	{
    		if(i==7) continue;
    		Node nxt=dfs(pos-1,(wei+i)%7,(sum*10+i)%7,lim&&(i==mx));
    		now.cnt=(now.cnt+nxt.cnt)%mod;
    		now.sum=(now.sum+(i*temp[pos]%mod*nxt.cnt%mod+nxt.sum)%mod)%mod;
                    //原先的sum+单选i的贡献*后面的cnt(即i的重复次数)+后面的sum
    		now.po=(now.po + nxt.po + i*temp[pos]%mod*i%mod*temp[pos]%mod*nxt.cnt%mod)%mod;
    		now.po=(now.po+2*i*temp[pos]%mod*nxt.sum%mod)%mod;
                    //计算nxt.sum时已经重复过nxt.cnt次所以这一步不用乘nxt.cnt
    	}
    	if(!lim) f[pos][wei][sum]=now;
    	return now;
    }
    ll dp(ll maxx)
    {
    	sum=0; x=maxx;
    	while(x) {a[++sum]=x%10;x/=10;}
    	return dfs(sum,0,0,1).po;
    }
    int main()
    {
    //	freopen("seven.in","r",stdin);
    //	freopen("seven.out","w",stdout);
    	read(T);
    	temp[1]=1LL;
    	for(int i=2;i<=20;++i) temp[i]=temp[i-1]*10%mod;
    	while(T--)
    	{
    		read(n);read(m);
    		printf("%lld
    ",((dp(m)-dp(n-1))%mod+mod)%mod);	
    	}
    	return 0;
    }
    
  • 相关阅读:
    LeetCode 275. H-Index II
    LeetCode 274. H-Index
    LeetCode Gray Code
    LeetCode 260. Single Number III
    LeetCode Word Pattern
    LeetCode Nim Game
    LeetCode 128. Longest Consecutive Sequence
    LeetCode 208. Implement Trie (Prefix Tree)
    LeetCode 130. Surrounded Regions
    LeetCode 200. Number of Islands
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11203662.html
Copyright © 2011-2022 走看看