题目链接:https://vjudge.net/problem/HDU-4507

题意:定义如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
  1、整数中某一位是7;

  2、整数的每一位加起来的和是7的整数倍;

  3、这个整数是7的整数倍;

  给定l,r,求[l,r] 区间与7无关的数的平方和。

思路:这3条定义都是常规的数位dp,但题目求的并不是与7无关的数的个数,而是平方和,这也是该题的难点。这里需要数位dp维护3个值:

  1. 与7无关的数的个数num;

  2. 与7无关的数的和sum;

  3. 与7无关的数的平方和sum;

  (用结构体组织上述3个属性,假设当前求的结点是ans,当前点取i,递归得到的结点为tmp)

  第1条很简单,就是常规的数位dp:

    ans.num+=tmp.num;
    ans.num%=Mod;

  第2条需要用到第一条,求当前的所有数的和,即后面位的所有和+当前值×后面的数的个数:

    ans.sum+=(tmp.sum+(i*key[pos])%Mod*tmp.num%Mod)%Mod;
    ans.sum%=Mod;

  第3条需要用到前2条,求当前所有数的平方和。先考虑一个数,设该数后面的位数的值为b,当前要加的值为a(a=i*key[pos]),则该数平方和为(a+b)^2=a^2+2*a*b+b^2,然后考虑对所有数的平方和,即上述式子求和tmp.num次,上述式子有3项。第一项:即a^2*tmp.num。第二项:即2*a*tmp.sum。第三项:即tmp.sqsum。

        ans.sqsum+=tmp.num*i%Mod*i%Mod*key[pos]%Mod*key[pos]%Mod;
ans.sqsum%=Mod;
ans.sqsum+=*i*key[pos]%Mod*tmp.sum%Mod;
ans.sqsum%=Mod;
ans.sqsum+=tmp.sqsum;
ans.sqsum%=Mod;

还有要注意的是这道题的数据,因为num,sum,sqsum还有key[i]都可能超过Mod,所以每乘一次就要%Mod,不然会出现乘法溢出。

AC代码:

#include <cstdio>
using namespace std;
typedef long long LL;
const LL Mod=; struct node{
LL num,sum,sqsum;
}dp[][][]; int T,a[];
LL key[]; node dfs(int pos,int pre1,int pre2,bool limit){
if(pos==-){
node tmp;
tmp.num=(pre1!=&&pre2!=);
tmp.sum=tmp.sqsum=;
return tmp;
}
if(!limit&&dp[pos][pre1][pre2].num!=-)
return dp[pos][pre1][pre2];
int up=limit?a[pos]:;
node ans;
ans.num=ans.sum=ans.sqsum=;
for(int i=;i<=up;++i){
if(i==) continue;
node tmp=dfs(pos-,(pre1+i)%,(pre2*+i)%,limit&&i==a[pos]); ans.num+=tmp.num;
ans.num%=Mod; ans.sum+=(tmp.sum+(i*key[pos])%Mod*tmp.num%Mod)%Mod;
ans.sum%=Mod; ans.sqsum+=tmp.num*i%Mod*i%Mod*key[pos]%Mod*key[pos]%Mod;
ans.sqsum%=Mod;
ans.sqsum+=*i*key[pos]%Mod*tmp.sum%Mod;
ans.sqsum%=Mod;
ans.sqsum+=tmp.sqsum;
ans.sqsum%=Mod;
}
if(!limit) dp[pos][pre1][pre2]=ans;
return ans;
} LL solve(LL x){
int pos=;
while(x){
a[pos++]=x%;
x/=;
}
return dfs(pos-,,,true).sqsum;
} int main()
{
key[]=;
for(int i=;i<=;++i)
key[i]=(key[i-]*)%Mod;
for(int i=;i<;++i)
for(int j=;j<;++j)
for(int k=;k<;++k)
dp[i][j][k].num=-;
scanf("%d",&T);
while(T--){
LL l,r,ans;
scanf("%lld%lld",&l,&r);
ans=solve(r)-solve(l-);
ans=(ans%Mod+Mod)%Mod;
printf("%lld\n",ans);
}
return ;
}

最新文章

  1. redis 集群热备自动切换sentinel配置实战
  2. Responsive设计——不同设备的分辨率设置
  3. 如何禁用Marlin温度保护
  4. Leetcode 38 Count and Say 传说中的递推
  5. PE文件数字签名信息读取存储及格式具体解释图之上(历史代码,贴出学习)
  6. Cyborg Genes
  7. NodeJS连接MongoDB数据库时报错
  8. data:image/png;base64是什么
  9. 帝国cms灵动标签调用tags
  10. mysql in查询 结果乱序 引发的思考
  11. dell 去鼠标版功能widnows
  12. Linux 安装Xampp以后,Apache服务器无法启动,以及启动后,连接sql数据库遇到的问题的解决方法
  13. JS函数与BOM
  14. shell脚本进阶之循环判断
  15. w3wp.exe已附加有调试器,但没有该调试器配置为调试此未经处理的异常,若要调试此异常,必须分离当前的调试器。
  16. 【慕课网实战】六、以慕课网日志分析为例 进入大数据 Spark SQL 的世界
  17. 洗礼灵魂,修炼python(90)-- 知识拾遗篇 —— 协程
  18. find ctime 加减n时间范围
  19. 初识docker-镜像
  20. C++读写TXT文件中的string或者int型数据以及string流的用法

热门文章

  1. [人物存档]【AI少女】【捏脸数据】写实系列
  2. k8b部署prometheus+grafana
  3. CSS颜色透明度
  4. BZOJ 4668: 冷战 并查集启发式合并/LCT
  5. 【转】稳定婚姻问题(Stable Marriage Problem)
  6. Android_(游戏)打飞机02:游戏背景滚动
  7. 并发编程--Concurrent-工具类介绍
  8. Contacts解析
  9. 【转】一款开源免费跨浏览器的视频播放器--videojs使用介绍
  10. Java_IO流实验