数位 dp trick

upt:本质上是有加法,所以会产生进位,所以你要从低位到高位做,然后因为每个位的进位数是 O(n) 的,所以保证你记忆化复杂度正确。

CF1290F Making Shapes

考虑凸包,向量集合确定了就能确定唯一凸包。

考虑向量加法转化到最后就是 xi>0cixi=xi<0cixi,yi>0ciyi=yi<0ciyi,xi>0cixim,yi>0ciyim

这里 trick 就是用数位 dp 的方式去解决 c 的方案。

先考虑在 10 进制下怎么做?

因为有进位,意味着我们要从低位到高位确定 ci,假如当前到了第 pos 位,那么从 [0,9] 枚举,然后使得其符合条件(每一位都要满足当前位的 xi>0cixi=xi<0cixi,yi>0ciyi=yi<0ciyi ,做类似十进制下的加法运算(维护每一个 sum 的进位)即可。

更优地,即在二进制下做加法。

#include <bits/stdc++.h> #define int long long #define pb push_back using namespace std; const int mod=998244353; int n,m,a[6],b[6],xgf[100002][6],tot,NW[6]; int f[10][23][23][23][23][2][2]; int get(int x,int y) { while(y) x/=10,--y; return x%10; } bool check(int x,int y,bool fl) { if(x!=y) return x<y?0:1; return fl; } int dfs(int pos,int sum1,int sum2,int sum3,int sum4,bool lim1,bool lim2) { //sum1 sum2 x 正 x 负 // if(sum1) cout<<pos<<" "<<sum1<<" "<<sum2<<" "<<sum3<<" "<<sum4<<endl; if(pos==10) return (!sum1&&!sum2&&!sum3&&!sum4&&!lim1&&!lim2); if(~f[pos][sum1][sum2][sum3][sum4][lim1][lim2]) return f[pos][sum1][sum2][sum3][sum4][lim1][lim2]; int qwq=get(m,pos); // cout<<qwq<<endl; f[pos][sum1][sum2][sum3][sum4][lim1][lim2]=0; for(int i=1;i<=tot;i++) { int res1=sum1,res2=sum2,res3=sum3,res4=sum4; for(int j=1;j<=n;j++) { if(a[j]>0) res1+=xgf[i][j]*a[j]; if(a[j]<0) res2-=xgf[i][j]*a[j]; if(b[j]>0) res3+=xgf[i][j]*b[j]; if(b[j]<0) res4-=xgf[i][j]*b[j]; } // cout<<res1<<" "<<res2<<" : "<<res3<<" "<<res4<<endl; if((res1%10)==(res2%10)&&(res3%10)==(res4%10)) { f[pos][sum1][sum2][sum3][sum4][lim1][lim2]=(f[pos][sum1][sum2][sum3][sum4][lim1][lim2]+dfs(pos+1,res1/10,res2/10,res3/10,res4/10,check(res1%10,qwq,lim1),check(res3%10,qwq,lim2)))%mod; } } return f[pos][sum1][sum2][sum3][sum4][lim1][lim2]; } void init(int x) { if(x==n+1) { ++tot; for(int i=1;i<=n;i++) xgf[tot][i]=NW[i]; // for(int i=1;i<=n;i++) cout<<NW[i]<<' '; // cout<<'\n'; return ; } for(int i=0;i<=9;i++) NW[x]=i,init(x+1); } signed main() { // cin.tie(0); ios::sync_with_stdio(false); // cout<<tot<<endl; cin>>n>>m; init(1); memset(f,-1,sizeof(f)); for(int i=1;i<=n;i++) cin>>a[i]>>b[i]; cout<<(dfs(0,0,0,0,0,0,0)+mod-1)%mod; }
#include <bits/stdc++.h> #define int long long #define pb push_back using namespace std; const int mod=998244353; int n,m,a[6],b[6]; int f[31][21][21][21][21][2][2]; bool check(int x,int y,bool fl) { if(x!=y) return x<y?0:1; return fl; } int dfs(int pos,int sum1,int sum2,int sum3,int sum4,bool lim1,bool lim2) { //sum1 sum2 x 正 x 负 // if(sum1) cout<<pos<<" "<<sum1<<" "<<sum2<<" "<<sum3<<" "<<sum4<<endl; if(pos==30) return (!sum1&&!sum2&&!sum3&&!sum4&&!lim1&&!lim2); if(~f[pos][sum1][sum2][sum3][sum4][lim1][lim2]) return f[pos][sum1][sum2][sum3][sum4][lim1][lim2]; int qwq=(m>>pos)&1; // cout<<qwq<<endl; f[pos][sum1][sum2][sum3][sum4][lim1][lim2]=0; for(int S=0;S<(1<<n);S++) { int res1=sum1,res2=sum2,res3=sum3,res4=sum4; for(int j=1;j<=n;j++) { int c=(S>>(j-1))&1; if(a[j]>0) res1+=c*a[j]; if(a[j]<0) res2-=c*a[j]; if(b[j]>0) res3+=c*b[j]; if(b[j]<0) res4-=c*b[j]; } // cout<<res1<<" "<<res2<<" : "<<res3<<" "<<res4<<endl; if((res1&1)==(res2&1)&&(res3&1)==(res4&1)) { f[pos][sum1][sum2][sum3][sum4][lim1][lim2]=(f[pos][sum1][sum2][sum3][sum4][lim1][lim2]+dfs(pos+1,res1>>1,res2>>1,res3>>1,res4>>1,check(res1&1,qwq,lim1),check(res3&1,qwq,lim2)))%mod; } } return f[pos][sum1][sum2][sum3][sum4][lim1][lim2]; }//er signed main() { cin.tie(0); ios::sync_with_stdio(false); cin>>n>>m; memset(f,-1,sizeof(f)); for(int i=1;i<=n;i++) cin>>a[i]>>b[i]; cout<<(dfs(0,0,0,0,0,0,0)+mod-1)%mod; }

AT2272 [ARC066B] Xor Sum

考虑 (v,u),(a+b,ab),(2(a&b)+ab,ab),显然我们有 a&b=(vu)/2,且 (a&b)&(ab)=0,即 vu2&u=0

因为 vu,那么限制 v 做数位 dp 即可,v=2vu2+u,转移的时候让当前这一位的与为 0。

#include <bits/stdc++.h> #define int long long #define pb push_back using namespace std; const int mod=(int)(1e9+7); int n,ans,f[62][100][2]; bool check(int x,int y,bool fl) { if(x^y) return x<y?0:1; return fl; } int dfs(int pos,int sum,bool lim) { if(pos==62) return (!lim&&!sum); //没有达到上界且没有进位,因为这位必为 0 if(~f[pos][sum][lim]) return f[pos][sum][lim]; int qwq=(n>>pos)&1; f[pos][sum][lim]=(dfs(pos+1,sum>>1,check(sum&1,qwq,lim))+dfs(pos+1,(sum+1)>>1,check((sum+1)&1,qwq,lim))+dfs(pos+1,(sum+2)>>1,check((sum+2)&1,qwq,lim)))%mod; return f[pos][sum][lim]; } signed main() { cin.tie(0); ios::sync_with_stdio(false); cin>>n; memset(f,-1,sizeof(f)); cout<<dfs(0,0,0); }

https://codeforces.com/contest/1670/problem/F

#include <bits/stdc++.h> #define int long long #define pb push_back #define il inline using namespace std; const int N=1002,mod=(int)(1e9+7); int f[60][2][5000]; int n,m,L,R,z,C[N]; int fpow(int x,int y) { int res=1; x%=mod; while(y) { if(y&1) res=res*x%mod; y>>=1; x=x*x%mod; } return res; } int dfs(int pos,int Lim,int sum) { if(pos==60) { if(!sum&&!Lim) return 1; return 0; } if(sum>(m>>pos)) return 0; if(~f[pos][Lim][sum]) return f[pos][Lim][sum]; int qwq=(m>>pos)&1,res=0; if((z>>pos)&1) { for(int i=1;i<=n;i+=2) { int qaq=sum+i; int d=(qaq&1); if(d>qwq) res=(res+dfs(pos+1,1,qaq>>1)*C[i]%mod)%mod; if(d==qwq) res=(res+dfs(pos+1,Lim,qaq>>1)*C[i]%mod)%mod; if(d<qwq) res=(res+dfs(pos+1,0,qaq>>1)*C[i]%mod)%mod; } } else { for(int i=0;i<=n;i+=2) { int qaq=sum+i; int d=(qaq&1); if(d>qwq) res=(res+dfs(pos+1,1,qaq>>1)*C[i]%mod)%mod; if(d==qwq) res=(res+dfs(pos+1,Lim,qaq>>1)*C[i]%mod)%mod; if(d<qwq) res=(res+dfs(pos+1,0,qaq>>1)*C[i]%mod)%mod; } } return f[pos][Lim][sum]=res; } signed main() { cin.tie(0); ios::sync_with_stdio(false); cin>>n>>L>>R>>z; C[0]=1; for(int i=0;i<n;i++) C[i+1]=C[i]*(n-i)%mod*fpow(i+1,mod-2)%mod; memset(f,-1,sizeof(f)); m=R; int ans=dfs(0,0,0); memset(f,-1,sizeof(f)); m=L-1; ans=(ans-dfs(0,0,0))%mod; ans=(ans%mod+mod)%mod; cout<<ans; return 0; }

__EOF__

本文作者F x o r G
本文链接https://www.cnblogs.com/xugangfan/p/16218224.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   FxorG  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示