@morehigh
2017-05-27T23:45:02.000000Z
字数 3213
阅读 1074
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;
}