hdu 4507 吉哥系列故事——恨7不成妻

2024-01-21 05:04
文章标签 系列 故事 hdu 4507 吉哥

本文主要是介绍hdu 4507 吉哥系列故事——恨7不成妻,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

吉哥系列故事——恨7不成妻

1

题意

一个正整数和 7 7 7 有关当且仅当满足以下条件之一

  • 数位中某一位是 7 7 7
  • 数位和能被 7 7 7 整除
  • 这个整数能被 7 7 7 整除

统计 [ l , r ] [l,r] [l,r] 内所有和 7 7 7 无关 的数字的 平方和

思路

这道题需要一点思维。我们先来看一个例子:

如果我们现在处理枚举 p o s pos pos 位为 p p p,低 p o s − 1 pos - 1 pos1 位的结果已经处理完了,在当前限制下,低 p o s − 1 pos - 1 pos1 的与 7 7 7 无关的数有: x 1 , x 2 , x 3 x_1,x_2,x_3 x1,x2,x3 三个的话,那么它们的平方和应该是: x 1 2 + x 2 2 + x 3 2 x_1 ^ 2 + x_2 ^ 2 + x_3 ^ 2 x12+x22+x32,现在我们要加上 p p p 的贡献,就是将 p p p 拼接上去, p p p 这一位的值是 p ⋅ 1 0 p o s − 1 p \cdot 10^{pos - 1} p10pos1,与 x 1 x_1 x1 拼接成: p x 1 px_1 px1,有: ( p x 1 ) 2 = ( p ⋅ 1 0 p o s − 1 + x 1 ) 2 = ( p ⋅ 1 0 p o s − 1 ) 2 + x 1 2 + 2 ⋅ x 1 ⋅ ( p ⋅ 1 0 p o s − 1 ) (px_1)^2 = (p \cdot 10^{pos-1} + x_1)^2 = (p \cdot 10^{pos-1})^2 + x_1 ^ 2 + 2 \cdot x1 \cdot (p \cdot 10^{pos - 1}) (px1)2=(p10pos1+x1)2=(p10pos1)2+x12+2x1(p10pos1)
其实这里就是一个完全平方公式。

那么我们转移就可以通过维护更低位的平方和 s 2 s_2 s2,符合条件的数有多少个 c n t cnt cnt,符合条件的数的 s 1 s_1 s1,三种信息。

转移就可以写成:
s 2 ′ = s 2 + 2 ⋅ s 1 ⋅ p ⋅ 1 0 p o s − 1 + c n t ⋅ ( p ⋅ 1 0 p o s − 1 ) 2 s_2\prime = s_2 + 2 \cdot s_1 \cdot p \cdot 10 ^{pos - 1} + cnt \cdot (p \cdot 10 ^ {pos -1})^2 s2=s2+2s1p10pos1+cnt(p10pos1)2
s 1 ′ = s 1 + c n t ⋅ p ⋅ 1 0 p o s − 1 s_1\prime = s_1 + cnt \cdot p \cdot 10 ^ {pos - 1} s1=s1+cntp10pos1
c n t ′ = c n t cnt\prime = cnt cnt=cnt

我们可以用 d p [ p o s ] [ r 1 ] [ r 2 ] dp[pos][r_1][r_2] dp[pos][r1][r2] 来表示 p o s pos pos 个全变化位, r 1 r_1 r1 为当前数位和模 7 7 7 的余数, r 2 r_2 r2 为当前数模 7 7 7 的余数条件下的信息。

搜到最底层时所有的位已经确定,所以节点只有一个信息 c n t = 1 cnt = 1 cnt=1 返回。
c n t cnt cnt 初始化为 − 1 -1 1 是为了记忆化,这里的 Z Z Z 类型当成是一个会自动取模的 l o n g l o n g long long longlong 就可以

时间复杂度: O ( l e n × 7 × 7 ) O(len \times 7 \times 7) O(len×7×7)

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n'
#define ull unsigned long long
#define ALL(v) v.begin(), v.end()
#define Debug(x, ed) std::cerr << #x << " = " << x << ed;const int INF=0x3f3f3f3e;
const long long INFLL=1e18;typedef long long ll;template<class T>
constexpr T power(T a, ll b){T res = 1;while(b){if(b&1) res = res * a;a = a * a;b >>= 1;}return res;
}constexpr ll mul(ll a,ll b,ll mod){ //快速乘,避免两个long long相乘取模溢出ll res = a * b - ll(1.L * a * b / mod) * mod;res %= mod;if(res < 0) res += mod; //误差return res;
}template<ll P>
struct MLL{ll x;constexpr MLL() = default;constexpr MLL(ll x) : x(norm(x % getMod())) {}static ll Mod;constexpr static ll getMod(){if(P > 0) return P;return Mod;}constexpr static void setMod(int _Mod){Mod = _Mod;}constexpr ll norm(ll x) const{if(x < 0){x += getMod();}if(x >= getMod()){x -= getMod();}return x;}constexpr ll val() const{return x;}explicit constexpr operator ll() const{ return x; //将结构体显示转换为ll类型: ll res = static_cast<ll>(OBJ)}constexpr MLL operator -() const{ //负号,等价于加上ModMLL res;res.x = norm(getMod() - x);return res;}constexpr MLL inv() const{assert(x != 0);return power(*this, getMod() - 2); //用费马小定理求逆}constexpr MLL& operator *= (MLL rhs) & { //& 表示“this”指针不能指向一个临时对象或const对象x = mul(x, rhs.x, getMod()); //该函数只能被一个左值调用return *this;}constexpr MLL& operator += (MLL rhs) & {x = norm(x + rhs.x);return *this;}constexpr MLL& operator -= (MLL rhs) & {x = norm(x - rhs.x);return *this;}constexpr MLL& operator /= (MLL rhs) & {return *this *= rhs.inv();}friend constexpr MLL operator * (MLL lhs, MLL rhs){MLL res = lhs;res *= rhs;return res;}friend constexpr MLL operator + (MLL lhs, MLL rhs){MLL res = lhs;res += rhs;return res;}friend constexpr MLL operator - (MLL lhs, MLL rhs){MLL res = lhs;res -= rhs;return res;}friend constexpr MLL operator / (MLL lhs, MLL rhs){MLL res = lhs;res /= rhs;return res;}friend constexpr std::istream& operator >> (std::istream& is, MLL& a){ll v;is >> v;a = MLL(v);return is;}friend constexpr std::ostream& operator << (std::ostream& os, MLL& a){return os << a.val();}friend constexpr bool operator == (MLL lhs, MLL rhs){return lhs.val() == rhs.val();}friend constexpr bool operator != (MLL lhs, MLL rhs){return lhs.val() != rhs.val();}
};const ll mod = 1e9 + 7;
using Z = MLL<mod>;struct node{Z cnt; //限制条件下与7无关的数字数量Z s1; //与7无关的数字的和Z s2; //与7无关的数字平方和node(ll cnt = -1, ll s1 = 0, ll s2 = 0): cnt(cnt), s1(s1), s2(s2) {}//cnt 初始化为 -1 是等价于memset的操作
};node dp[20][8][8];
int num[20];
Z ten[20];node dfs(int pos, int r1, int r2, bool limit){ //r1:当前数位和模7  r2:当前数模7if(!pos) return (r1 && r2 ? node(1) : node(0));if(!limit && dp[pos][r1][r2].cnt != -1) return dp[pos][r1][r2];node res(0);int up = (limit ? num[pos] : 9);fore(i, 0, up + 1){if(i == 7) continue;node nxt = dfs(pos - 1, (r1 + i) % 7, (r2 * 10 + i) % 7, limit && i == up);res.cnt += nxt.cnt;res.s1 += nxt.cnt * i * ten[pos - 1] + nxt.s1;res.s2 += nxt.s2 + nxt.cnt * i * i * ten[pos - 1] * ten[pos - 1];res.s2 += 2 * nxt.s1 * i * ten[pos - 1];}if(!limit) dp[pos][r1][r2] = res;return res;
}Z solve(ll x){int len = 0;while(x){num[++len] = x % 10;x /= 10;}return dfs(len, 0, 0, true).s2;
}int main(){std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout.tie(nullptr);ten[0] = 1;fore(i, 1, 19) ten[i] = ten[i - 1] * 10;int t;std::cin >> t;while(t--){ll l, r;std::cin >> l >> r;Z ans = solve(r) - solve(l - 1);std::cout << ans << endl;}return 0;
}

这篇关于hdu 4507 吉哥系列故事——恨7不成妻的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/628436

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2093 考试排名(sscanf)

模拟题。 直接从教程里拉解析。 因为表格里的数据格式不统一。有时候有"()",有时候又没有。而它也不会给我们提示。 这种情况下,就只能它它们统一看作字符串来处理了。现在就请出我们的主角sscanf()! sscanf 语法: #include int sscanf( const char *buffer, const char *format, ... ); 函数sscanf()和

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

hdu 3790 (单源最短路dijkstra)

题意: 每条边都有长度d 和花费p,给你起点s 终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。 解析: 考察对dijkstra的理解。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstrin

hdu 2489 (dfs枚举 + prim)

题意: 对于一棵顶点和边都有权值的树,使用下面的等式来计算Ratio 给定一个n 个顶点的完全图及它所有顶点和边的权值,找到一个该图含有m 个顶点的子图,并且让这个子图的Ratio 值在所有m 个顶点的树中最小。 解析: 因为数据量不大,先用dfs枚举搭配出m个子节点,算出点和,然后套个prim算出边和,每次比较大小即可。 dfs没有写好,A的老泪纵横。 错在把index在d