zoukankan      html  css  js  c++  java
  • 恨 7 不成妻

    https://loj.ac/problem/10168

    题目描述

      求出一段区间内与(7)无关的数的平方和,我们定义这个数与(7)有关当且仅当这个数满足下列条件之一:1、某一位为(7);2、数位和为(7)的倍数;3、这个数本身是(7)的倍数。

    思路

      这题并不算裸的数位(dp)题,显然如果对于计数我们很容易得到这个区间内满足条件的个数,而为了使数位(dp)(dp)能够有子状态重叠,我们仍然考虑计数,不过对于每一位的处理可以转化为记录它的状态,我们用一个三元组((cnt,sum,sqsum))描述这个状态,它代表这这个状态下符合条件的数的个数(cnt),这后几位数的和对答案的贡献,后几位的平方和对答案的贡献。显然(cnt)可以直接求出来。

      而对于另两个值,我们考虑当前位为(pos),选取的值为(i)(tmp)为传回来的答案,那么显然(ans.sum=(ans.sum+tmp.cnt*10^{pos}*i)),因为每一个符合条件的数这一位都为(i),对和有(i*10^{pos})的贡献。而对于平方和,我们要求的实际就是(sum(i*10^{pos}+x)^2)((x)符合条件),所以我们暴力把它拆开,得到(sum (i^2*10^{2*pos}+2*i*10^{pos}*x+x^2)),再把求和拆开得(sum i^2*10^{2*pos}+sum 2*i*10^{pos}*x+sum x^2),这个我们可以用得到的三元组((cnt,sum,sqsum))直接转移。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=1e9+7;
    
    struct Node
    {
    	ll cnt,sum,sqsum;
    	Node(ll cnt=0,ll sum=0,ll sqsum=0):cnt(cnt),sum(sum),sqsum(sqsum){}
    };
    Node dp[31][11][11];
    ll p[30];
    ll power[30];
    
    ll sqr(ll x)
    {
    	return x*x%mod;
    }
    Node dfs(ll pos,ll s1,ll s2,ll flag)
    {
    //	cout<<pos<<'z'<<endl;
    	if(pos==0)
    		return Node(s1!=0&&s2!=0,0,0);
    	if(!flag&&~dp[pos][s1][s2].cnt)return dp[pos][s1][s2];
    	Node tmp,ans=Node(0,0,0);
    	ll end=flag?p[pos]:9;
    //	cout<<pos<<' '<<end<<endl;
    	for(ll i=0;i<=end;i++)
    	{
    		if(i==7)continue ;
    		tmp=dfs(pos-1,(s1+i)%7,(s2*10+i)%7,flag&&i==end);
    		ans.cnt+=tmp.cnt;
    		ans.cnt%=mod;
    		ans.sum+=(tmp.sum+tmp.cnt*power[pos]%mod*i%mod)%mod;
    		ans.sum%=mod;
    		ans.sqsum+=(tmp.sqsum+2*power[pos]*i%mod*tmp.sum%mod+sqr(i)*sqr(power[pos])%mod*tmp.cnt%mod)%mod;
    		ans.sqsum%=mod;
    	}
    	if(!flag)dp[pos][s1][s2]=ans;
    	return ans;
    }
    ll solve(ll x)
    {
    	memset(p,0,sizeof(p));
    	ll cnt=0;
    	while(x)
    	{
    		p[++cnt]=x%10;
    		x/=10;
    	}
    	return dfs(cnt,0,0,1).sqsum;
    }
    
    ll read()
    {
    	ll res=0,w=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
    	return res*w;
    }
    void write(ll x)
    {
    	if(x<0){putchar('-');x=-x;}
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    }
    void writeln(ll x)
    {
    	write(x);
    	putchar('
    ');
    }
    
    int main()
    {
    	ll t=read();
    	power[1]=1;
    	for(ll i=2;i<=21;i++)
    		power[i]=(power[i-1]*10)%mod;
    	for(ll i=0;i<=21;i++)
    		for(ll j=0;j<=10;j++)
    			for(ll k=0;k<=10;k++)
    				dp[i][j][k].cnt=-1;
    	while(t--)
    	{
    		ll l=read(),r=read();
    		writeln(((solve(r)-solve(l-1))%mod+mod)%mod);
    	}
    }
    
  • 相关阅读:
    java zxing生成二维码
    忘记MySQL root密码重置MySQL root密码
    Java通过ScriptEngine 执行js脚本案例
    两个自定义对象List列表取交集(intersection)
    Java 判断Windows下某个进程是否运行
    Layer文件上传操作
    Jmeter AbstractJavaSamplerClient 案例
    Jaspersoft Studio 导出PDF格式中文不显示
    使用gradle的application插件进行Spring-boot项目打包
    jQuery Ajax应用总结
  • 原文地址:https://www.cnblogs.com/fangbozhen/p/11844402.html
Copyright © 2011-2022 走看看