@morehigh
2017-05-27T15:45:02.000000Z
字数 3213
阅读 1221
DP
B - XHXJ's LIS HDU - 4352
输入的L,R,K.(0<L<=R<2^63-1 and 1<=K<=10),表示一个数字拆分成位数(个,十,百。。)满足长度为K的递增的序列,求出从L到R的满足条件的数字的个数。
数位dp+状态压缩,dp[pos][st][k]=ans,表示位数为pos,状态为st,上升子序列长度为k的个数为ans,其中用到位运算是为了解决上升序列状态,然后根据状态中1的个数可以算出上升序列的长度。
#include <bits/stdc++.h>using namespace std;typedef long long ll;ll dp[50][1<<10][15];ll l,r,k;ll a[50];int getst(int st,int x){for(int i=x;i<10;i++)if(st&(1<<i)) return ((st^(1<<i))|(1<<x));return st|(1<<x);}ll getlen(int st){int cnt=0;while(st){if(st&1) cnt++;st>>=1;}return cnt;}ll dfs(int pos,int st,int zero,int f){if(pos<1) return getlen(st)==k;if(!f&&dp[pos][st][k]!=-1) return dp[pos][st][k];int las= f?a[pos]:9;ll ans=0;for(int i=0;i<=las;i++){ans+=dfs(pos-1,(zero==0&&i==0)?0:getst(st,i),zero||i,f&&(i==las));}if(!f) dp[pos][st][k]=ans;return ans;}ll sol(ll x){int len=0;while(x){a[++len]=x%10;x/=10;}return dfs(len,0,0,1);}int main(){int t,cas=1;scanf("%d",&t);memset(dp,-1,sizeof(dp));while(t--){scanf("%lld%lld%lld",&l,&r,&k);printf("Case #%d: %lld\n",cas++,sol(r)-sol(l-1));}return 0;}
C - Brackets Sequence POJ - 1141
左右括号匹配问题,给出一串字符,求出最少添加多少个括号,能使全部括号匹配,满足条件。
d[i][j]表示在区间i到j中有最少加多少个括号使得全部括号达到匹配,c[i][j]表示在i,j中添加括号的位置,d[i][j]=min(d[i][j],d[i][k]+d[k+1][j]);if(ss[i]=='('&&ss[j]==')'||ss[i]=='['&&ss[j]==']') d[i][j]=d[i+1][j-1]; 区间i,j暂时不用插入括号。
#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <algorithm>using namespace std;string ss;int len;int d[100][100];int c[100][100];void sol(){int mn,j;memset(d,0,sizeof(d));for(int i=0;i<len;i++) d[i][i]=1;for(int l=1;l<len;l++){for(int i=0;i+l<len;i++){j=i+l;d[i][j]= 0x7fffffff;for(int k=i;k<j;k++){if(d[i][k]+d[k+1][j]<d[i][j]){d[i][j]=d[i][k]+d[k+1][j];c[i][j]=k;}}// d[i][j]=mn;if(ss[i]=='('&&ss[j]==')'||ss[i]=='['&&ss[j]==']'){if(d[i+1][j-1]<d[i][j]){d[i][j]=d[i+1][j-1];c[i][j]=-1;}}}}}void print(int i,int j){if(i>j) return ;if(i==j){if(ss[i]=='('||ss[i]==')') cout<<"()";else cout<<"[]";}else{if(c[i][j]>=0){print(i,c[i][j]);print(c[i][j]+1,j);}else{if(ss[i]=='('){cout<<"(";print(i+1,j-1);cout<<")";}else{cout<<"[";print(i+1,j-1);cout<<"]";}}}}int main(){cin>>ss;len =ss.size();sol();// cout<<d[0][len-1]<<endl;print(0,len-1);cout<<endl;return 0;}
E - Little Elephant and Elections
要在7个政党中进行选举,小象政党认为4和7是幸运数字,每个政党将被分配一个数字,若小象政党中幸运数字的个数大于其他6个政党幸运数字的个数,有多少中正确的分配方式满足条件。
首先确定第七个数的lucky值,然后分别枚举其他六个数的情况。确定了第七个数,我们就可以利用dfs深搜出每种符合条件的结果并且将结果加到ans中。
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int mod=1000000007;ll dp[20][20];ll res[20];int bit[20],num;ll ans;void DFS(ll now,int mx,int pt,ll cur){if(now>=mx)//如果其他的lucky超过小象政党的lucky值,跳出return ;if(pt==7){if(now<mx){ans+=cur;ans%=mod;}return ;}for(int i=0;i<num;i++){if(res[i]){res[i]--;DFS(now+i,mx,pt+1,cur*(res[i]+1)%mod);res[i]++;}}}ll dfs(ll pos,ll mx,ll limit){ll sum=0;if(pos==0) return mx==0;if(limit==0&&dp[pos][mx]!=-1)return dp[pos][mx];ll las=limit?bit[pos]:9;for(int i=0;i<=las;i++){sum+=dfs(pos-1,mx-(i==4||i==7),(limit==1&&bit[pos]==i));}if(!limit) dp[pos][mx]=sum;//位数为pos,lucky数为mx时的种类数return sum;}void col(ll m){ans=num=0;ll y=m;while(y){bit[++num]=y%10;y/=10;}for(int i=0;i<=num;i++)res[i]=dfs(num,i,1); //小象政党最多获得的lucky值为num,res[i]表示lucky值为i的数字的个数res[0]-=1;for(int i=1;i<=num;i++)DFS(0,i,1,res[i]); //当小象政党的lucky值为i时,其他6个政党的lucky和小于i的方案数}int main(){ll m;memset(dp,-1,sizeof(dp));scanf("%lld",&m);col(m);printf("%lld\n",ans);return 0;}