HDU 4352
数位dp结合o(nlogn)的最长严格递增子序列
给定一个数的价值为 将该数字看成一个由单个数字排列成的序列,其最长严格递增子序列的长度就是该数的价值
给定一个区间 求该区间内价值为k的有多少个
nlogn的最长严格递增子序列的求法可以自行百度
#include <stdio.h> #include <string.h> #define LL __int64 int dit[50],K; LL dp[19][2049][11]; void init() { for(int i=0;i<19;++i) { for(int j=0;j<(1<<10);++j) { for(int k=0;k<11;++k) { dp[i][j][k] = -1; } } } } LL dfs(int limit,int sta,int pos,int k) { //printf("%d %d %d\n",sta,pos,k); if(pos<0) return k==K; if(!limit&&dp[pos][sta][K]!=-1) return dp[pos][sta][K]; int end=limit?dit[pos]:9; LL sum=0; for(int i=0;i<=end;i++) { if(i==0&&sta==0) { sum+=dfs(limit&&(i==end),0,pos-1,k); } else if((1<<i)&sta) { sum+=dfs(limit&&(i==end),sta,pos-1,k); } else if((1<<i)>sta) { sum+=dfs(limit&&(i==end),sta|(1<<i),pos-1,k+1); } else { int nst=0; for(int j=i+1; j<=9; j++) { if((1<<j)&sta) { nst=(sta|(1<<i))^(1<<j); break; } } sum+=dfs(limit&&(i==end),nst,pos-1,k); } } if(!limit) dp[pos][sta][K]=sum; return sum; } LL cal(LL n) { int cnt=0; while(n>0) { dit[cnt++]=n%10; n/=10; } return dfs(1,0,cnt-1,0); } int main() { int t,ca=0; scanf ("%d",&t); init(); while(t--) { LL l,r; ca++; scanf ("%I64d%I64d%d",&l,&r,&K); printf("Case #%d: %I64d\n",ca,cal(r)-cal(l-1)); } }HDU 4357
该题可以推出结论 当字母多于3个时,其中任意两个可以互换
这样只需要特殊处理只有两个字母的情况就可以了
#include<stdio.h> #include <string.h> int main () { char s1[100],s2[100]; int t; scanf ("%d",&t); for(int ca=1;ca<=t;ca++) { scanf ("%s%s",s1,s2); int len=strlen(s1); if(len>2) { int sum=0; for(int i=0;i<len;i++) sum+=(s1[i]-'a'+s2[i]-'a'); if(sum&1) printf("Case #%d: NO\n",ca); else printf("Case #%d: YES\n",ca); } else { int ans1=s2[0]-s1[1]+52; int ans2=s2[1]-s1[0]+52; int ans3=s2[0]-s1[0]+52; int ans4=s2[1]-s1[1]+52; if((ans1==ans2&&(ans1&1))||(ans3==ans4&&(ans3%2==0))) printf("Case #%d: YES\n",ca); else printf("Case #%d: NO\n",ca); } } }HDU4359
这道是组合数学以及动态规划
由于2的n次方大于1到n-1次方的和
所以只需要将2的n次方放在右子树即可满足题目要求
剩下的就是分配子树节点个数
没了