数位dp 完结撒花!
明天开始单调队列优化dp 这个还以前做过几道题
数位dp 可以说是一个全新的模型 第一次接触
本来以为会是很套路的模板 不过确实很套路
但最后一题的难度感觉 已经超过了我自己的能力范围
但我还是花了几个小时的时间去搞懂他
想起了xyx说的“瓶颈”
也听说过另一个XYX说的 去做你刚好做又不能做的题 很抽象
不过也不算难看 这道题
感觉做完不知道这么说
好像是有点成就感 但更多的是担心下次再遇到这种难度的题 我会束手无措
只是停留在做原题 是不正确的
希望自己能成为xyx说的特别的人 不是前仆后继者
思路一样的
状态表示加一维总和即可
状态计算:f[i][j][k]+=f[i-1][x][k-j];
不过这里要mod 把负的变成正的
那我们可以自己写一个mod return (x%p+p)%p;
还要一个边界判断 我们这里可以清楚的知道0肯定是一个合法方案 所以return 1即可
但是昨天那个windy数 0也是一个合法方案 为啥return 0呢
那是因为我们后面也相当于整了一棵树 return 就相当于没把 0 纳入考虑的范围
那么我们后面就可以少写一个特判
- #include
- using namespace std;
- const int N = 15;
- const int M = 1<<12;
- //const int mod = 1e9+7;
- #define int long long
- #define endl '\n'
- #define Endl '\n'
- #define _ 0
- #define inf 0x3f3f3f3f3f3f3f3f
- #define fast ios::sync_with_stdio(false);cin.tie(nullptr);
- int f[N][N][110],l,r,p;//f[i][j][k]表示i位首位为j并且mod p和为k的合法方案数
- int mod(int x,int P){
- return (x%P+P)%P;
- }
- void init(){
- memset(f,0,sizeof f);
- for(int i=0;i<=9;i++)f[1][i][i%p]++;
- for(int i=2;i
- for(int j=0;j<=9;j++){
- for(int k=0;k
- for(int x=0;x<=9;x++){
- f[i][j][k]+=f[i-1][x][mod(k-j,p)];
- }
- }
- }
- }
- }
- int dp(int n){
- if(!n)return 1;
- vector<int>v;
- while(n)v.push_back(n%10),n/=10;
- int res=0,last=0;
- for(int i=v.size()-1;i>=0;i--){
- int x=v[i];
- for(int j=0;j
- res+=f[i+1][j][mod(-last,p)];
- }
- last+=x;
- if(!i&&last%p==0)res++;
- }
- return res;
- }
- signed main(){
- fast
- while(cin>>l>>r>>p){
- init();
- cout<<dp(r)-dp(l-1)<
- }
- return ~~(0^_^0);
- }
1085. 不要62
这个还挺简单的
最开始一看到这个就想到了状态机+KMP 可是一看居然只有两个字符串 而且都才一两位
那我们就可以直接做了
注意一点就是我们枚举j的时候有可能此位是345679 j自然就有2这种情况 而如果last是6的话自然要skip掉 因为我们加的时候只是n位上首位为2的 没有包括前面6这个限制条件 所以还是有值的
细节很多啊!
不光是后面的break 看来还需磨练啊!
- #include
- using namespace std;
- const int N = 15;
- const int M = 1<<12;
- const int mod = 1e9+7;
- #define int long long
- #define endl '\n'
- #define Endl '\n'
- #define _ 0
- #define inf 0x3f3f3f3f3f3f3f3f
- #define fast ios::sync_with_stdio(false);cin.tie(nullptr);
- int f[N][N],l,r;
- void init(){
- for(int i=0;i<=9;i++)f[1][i]=1;
- f[1][4]=0;
- for(int i=2;i
- for(int j=0;j<=9;j++){
- if(j==4)continue;
- else if(j==6){
- for(int k=0;k<=9;k++){
- if(k!=2)f[i][j]+=f[i-1][k];
- }
- }else{
- for(int k=0;k<=9;k++){
- f[i][j]+=f[i-1][k];
- }
- }
- }
- }
- }
- int dp(int n){
- if(!n)return 1;
- vector<int>v;
- while(n)v.push_back(n%10),n/=10;
- int res=0,last=0;
- for(int i=v.size()-1;i>=0;i--){
- int x=v[i];
- for(int j=0;j
- if(last == 6 && j == 2)continue;
- res+=f[i+1][j];
- }
- if(x==4||(x==2&&last==6))break;
- last=x;
- if(!i)res++;
- }
- return res;
- }
- signed main(){
- fast
- init();
- while(cin>>l>>r,l&&r){
- cout<<dp(r)-dp(l-1)<
- }
- return ~~(0^_^0);
- }
1086. 恨7不成妻
哈哈 全局变量的结构体居然还要引用才可以修改
2:任意一个数与last_a或者last_b关于p互补都不是合法的
3:算res时要把前面的位数算进去那么就相当于j换成了last_a * power9[i+1]
4:我们最后树的右边应该是他自己的平方和
回到这道题本身
我们可以轻松的推出状态表示 前i位 首位为j 每位sum为k 总sum为m的平方和
最开始我以为状态转移就是加上每一位的平方和就可以了
看来还是我太傻逼了(就像是10001^2 == 10000^2 +1^2)
肯定是错误的!
我们把当前为jXXXXX.... 我们抽象把后面的i-1位 成一个数 A
合法的解的平方和=jA1^2+jA2^2+jA3^2+....+jAt^2 (jA=j*10^(i-1)+A)
=t(j*10^(i-1))^2+2*(j*10^(i-1))*(A1+A2+A3+....+At)+(A1^2+A2^2+...)
如果我们只维护平方和 那我们的下一个平方和是递推不出来的
看上式 我们还需要维护的有t 还有(A1+A2+A3+....+At) 这个暂且称为数的和
好 接下来那我们如何 维护这些信息呢
我们先把状态转移方程写下来:
f[i][j][k][m]<-f[i-1][x][k-j][m-j*10^i-1]
v1 v2
我们分别把要维护的三个信息 写成结构体的形式 //s0 cnt s1 sum s2 sqrt sum
合法的数量 自然只用 v1.s0+=v2.s0 即可 这里是可以%p的 这里我一开始想的是不能%
但其实你的cnt都要拿进去算 并且又没有除法 当然可以直接%掉
v1.s1 即是i位j首位的数的总和 我们知道v2的数量 并且v2的前面接的就是v1的j
v1.s1+=v2.s0*j*10^i-1+v2.s1;
v1.s2就要用最开始的那个方程来算了t(j*10^(i-1))^2+2*(j*10^(i-1))*(A1+A2+A3+....+At)+(A1^2+A2^2+...)
预处理结束
正式开始我们的树
我们用last1存前面位的前缀 last2存前面位sum
当然我们进去时要把a=-last1*10^i%7 b=-last2%7
算出我们不可以凑到的a b 其实就是一个互补的关系 这里取负号 最开始我没看到符号我一直以为他写反了 哈哈
然后我们要把满足该位满足要求的所有数取出来
这里取出来就是同一位上面的 直接+上就可以了
让后我们就相当于有个前缀last1而不是最开始j了
最后要是出现 7 break 掉 否则更新last1 last2
注意这里last1一直让他从小的位数开始 其实也可以直接i位开始 感觉会更好写一点
最后有幸走到右边树 并且都是合法的 那么我们加上原本数的平方和即可
完结撒花!
- #include
- using namespace std;
- const int N = 20;
- const int M = 1<<12;
- //const int mod = 1e9+7;
- #define int long long
- #define LL long long
- #define endl '\n'
- #define Endl '\n'
- #define _ 0
- #define inf 0x3f3f3f3f3f3f3f3f
- #define fast ios::sync_with_stdio(false);cin.tie(nullptr);
- struct F{
- int s0,s1,s2; //s0 cnt s1 sum s2 sqrt sum
- }f[N][10][7][7];
- int p=1e9+7,power7[N],power[N];
- int mod(int x,int y){
- return (x%y+y)%y;
- }
- void init(){
- power7[0]=power[0]=1;
- for(int i=1;i
- power7[i]=power7[i-1]*10%7;
- power[i]=power[i-1]*10%p;
- }
- for(int i=0;i<=9;i++){
- if(i==7)continue;
- auto &v=f[1][i][i%7][i%7];
- v.s0++;
- v.s1+=i;
- v.s2+=i*i;
- }
- int power1=10;
- for(int i=2;i
10){ - for(int j=0;j<=9;j++){
- if(j==7)continue;
- for(int k=0;k<7;k++){
- for(int m=0;m<7;m++){
- for(int x=0;x<=9;x++){
- if(x==7)continue;
- auto &v1=f[i][j][k][m],&v2=f[i-1][x][mod(k-j*mod(power1,7),7)][mod(m-j,7)];
- v1.s0=(v1.s0+v2.s0)%p;
- v1.s1=(v1.s1+v2.s0*j%p*(power1%p)+v2.s1)%p;
- v1.s2=(v1.s2+j*j%p*(power1%p)%p*(power1%p)%p*v2.s0%p+2*j*(power1%p)%p*v2.s1%p+v2.s2)%p;
- }
- }
- }
- }
- }
- }
- F get(int i,int j,int k,int m){
- int s0=0,s1=0,s2=0;
- for(int x=0;x<7;x++){
- for(int y=0;y<7;y++){
- if(k==x||y==m)continue;
- else{
- auto v=f[i][j][x][y];
- s0=(s0+v.s0)%p;
- s1=(s1+v.s1)%p;
- s2=(s2+v.s2)%p;
- }
- }
- }
- return {s0,s1,s2};
- }
- int dp(int n){
- if(!n)return 0;
- int cnt=n%p;
- vector<int>v;
- while(n)v.push_back(n%10),n/=10;
- int res=0,last_a=0,last_b=0;
- for(int i=v.size()-1;i>=0;i--){
- int x=v[i];
- int a=mod(-last_a*power7[i+1],7);
- int b=mod(-last_b,7);
- for(int j=0;j<x;j++){
- if(j==7)continue;
- auto v1=get(i+1,j,a,b);
- res=(res +
- (last_a % p) * (last_a % p) % p * (power[i + 1] % p) % p * (power[i + 1] % p) % p * v1.s0 % p +
- 2 * (last_a % p) * (power[i + 1] % p) % p * v1.s1 % p +
- v1.s2)%p;
- }
- if(x==7)break;
- last_a*=10,last_a+=x;
- last_b+=x;
- if(!i&&last_a%7&&last_b%7)res=(res+cnt*cnt)%p;
- }
- return res;
- }
- signed main(){
- fast
- init();
- int t;cin>>t;
- while(t--){
- int l,r;cin>>l>>r;
- cout<
1),p)< - }
- return ~~(0^_^0);
- }
-
相关阅读:
springboot集成mybatis
vue报错信息汇总
前端设计模式应应用场景
Git版本控制系统
scipy.io.matlab._streams.GenericStream.read_into OSError: could not read bytes
【并发编程五】c++进程通信——信号量(semaphore)
人血清白蛋白功能化纳米四氧化三铁Fe3O4
uni-app checkout(多选)radio(单选)选中之后样式不会出现钩子
flask框架
可见光相机曝光方式
-
原文地址:https://blog.csdn.net/qq_23852555/article/details/126071820