URAL 1057+HDU 2089(数位dp
URAL 1057
题目:求区间[l,r]内能表示成k个b的各不相同的幂的数有多少个。
思路:首先把上限数字换算成b进制,然后因为我们要求的不会有多个相同的幂,所以大于1的位直接把后面补齐为1。然后就是一个典型的数位dp。
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-14) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000300) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (b)) #define mset(x,v) memset((x),(v),sizeof (x)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; int x,y,k,b; vector<int> num,lim; int sz; ll dp[40][40][2]; void get(int v){ num.clear();lim.clear(); while(v>0){ num.pb(v%b); v/=b; } sz=num.size(); for(int i=sz-1;i>=0;i--){ if(num[i]==1||num[i]==0){ lim.pb(num[i]); }else{ for(;i>=0;i--){ lim.pb(1); } break; } } } ll dfs(int p,int n,bool l){ if(n>=k) return 1; if(p>=sz) return 0; ll &val=dp[p][n][l]; if(val!=-1) return val; val=0; if(!l){ val+=dfs(p+1,n,0)+dfs(p+1,n+1,0); }else{ if(lim[p]==1) val+=dfs(p+1,n+1,1)+dfs(p+1,n,0); else val+=dfs(p+1,n,1); } return val; } ll cal(int x){ mset(dp,-1);get(x); dfs(0,0,1); return dp[0][0][1]==-1?0:dp[0][0][1]; } int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); while(cin>>x>>y>>k>>b){ printf("%lld\n",cal(y)-cal(x-1)); } return 0; }
对于这个递归出口。。。当时写得时候似乎想得挺顺的。。。后来突然感觉意义不明。。。。。
补充一下:dp[i][j][k]表示正在做第i位,已经有j个1,k表示是否有限制。当时写这个出口的思路大概是这样的:不然怎么算都是0啊。。。大概可以这么解释:每次到达出口的时候对应一个不同的解(在前面确定的情况下)。由于我这个是倒着写的,总是感觉不太自然。。。。(如果把剩余数量到过来似乎更好理解,那么最后就表示剩0个空位的方法种数,显然是1)。
HDU 2089
题目:中文题目见上链接。
思路:裸数位dp。
/* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-14) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000300) #define FINF (1e3) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (b)) #define mset(x,v) memset((x),(v),sizeof (x)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; int n,m; vector<int> lim; void get(int v){ lim.clear(); while(v>0){ lim.pb(v%10); v/=10; } while(lim.size()<7) lim.pb(0); reverse(lim.begin(),lim.end()); } int dp[10][2][2]; int dfs(int p,bool l1,bool l2){ int &val=dp[p][l1][l2]; if(p>=7) return 1; if(val!=-1) return val; val=0; for(int i=0;i<lim[p];i++){ if(i==4) continue; if(i!=6&&i!=2) val+=dfs(p+1,0,0); if(i==6) val+=dfs(p+1,1,0); if(i==2&&!l1) val+=dfs(p+1,0,0); } if(l2){ int i=lim[p]; if(i!=4){ if(i!=6&&i!=2) val+=dfs(p+1,0,1); if(i==6) val+=dfs(p+1,1,1); if(i==2&&!l1) val+=dfs(p+1,0,1); } }else{ for(int i=lim[p];i<10;i++){ if(i==4) continue; if(i!=6&&i!=2) val+=dfs(p+1,0,0); if(i==6) val+=dfs(p+1,1,0); if(i==2&&!l1) val+=dfs(p+1,0,0); } } return val; } int cal(int x){ get(x);mset(dp,-1); dfs(0,0,1); return dp[0][0][1]; } int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); while(scanf("%d%d",&n,&m),(n||m)){ printf("%d\n",cal(m)-cal(n-1)); } return 0; }