1.题目链接:codeforces 55D
【题意】一个数能被它每一位的数字整除(0除外)则为beautiful number ,问[l,r]之间有多少个这样的数
【思路】考虑到每一位的数字只能是1,2,,9,最小公倍数为2520
设数w=x*2520+y,每位数字的最小公倍数为mul,则w%mul=(x*2520+y)%mul=x*2520%mul+y%mul=y%mul,只需要记录每一步过后该数对2520取模即可。
dp[len][y][mul]表示处理到第len位时数对2520的模,及当前所有数字的最小公倍数。可开到dp[20][2520][2520]
由于数字的最小公倍数是有限的,可将第三维2520进一步优化,预处理求出2520所有的约数。
优化为dp[20][2520[60]
/***********************************************************************
> File Name: cf55d.cpp
> Author: wanghao
> Mail: [email protected]
> Created Time: 2015年07月06日 星期一 15时27分54秒
************************************************************************/
#include
#include
#include
#define ll long long
using namespace std;
ll dp[20][2520][60];
int num[20];
int v[60],cnt;
int to[2600];
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
int lcm(int a,int b)
{
if(b==0)
return a;
return a*b/gcd(a,b);
}
ll dfs(int p,int y,int multi,int flag)
{
//cout<>a>>b;
cout<
2.题目链接:hdu4352
【题意】定义一个数的值为其数字最长上升子序列的长度,例如3746,最长上升序列为 3,4,6,值为3.求[l,r]个中值为k的数有多少个。
【思路】好题。。忍不住看了题解。。求最长上升子序列时,我们需要维护一个序列,表示长度为1的最后一个数的最小值,长度为2的最后一个数的最小值,长度为3的最后一个的最小值。。。这个序列是单调递增的,我们只需要记录下这个序列即可,只有0-9 10个数字,状态压缩!
/*************************************************************************
> File Name: hdu4352.cpp
> Author: wanghao
> Mail: [email protected]
> Created Time: 2015年07月09日 星期四 20时19分09秒
************************************************************************/
#include
#include
#include
#define ll long long
using namespace std;
ll dp[20][1<<10][11];
int num[20];
int k;
int getlen(int state)
{
int res=0;
for(int i=0;i<10;i++)
res+=(state&(1<=0;i--)
{
if(state&(1<=v)
return state^(1<len)return dp[p][state][len]=0;
ll res=0;
int u=flag?num[p]:9;
for(int i=0;i<=u;i++)
{
int now=update(state,i);
res+=dfs(p-1,now,len,flag&&i==num[p]);
}
// cout<
【题意】含4或62的数为不吉利数,求[l,r]中有多少个吉利的数
【思路】水题。。直接写
/*************************************************************************
> File Name: hdu2089.cpp
> Author: wanghao
> Mail: [email protected]
> Created Time: 2015年07月06日 星期一 15时58分40秒
************************************************************************/
#include
#include
#include
using namespace std;
int num[10];
int len;
int dp[10][2];
int dfs(int p,int flag,int flag2)
{
if(p==-1)
return 1;
if(!flag&&dp[p][flag2]!=-1)
return dp[p][flag2];
int u=flag?num[p]:9;
int res=0;
for(int i=0;i<=u;i++)
{
if(i==2&&!flag2)continue;
if(i==4)continue;
res+=dfs(p-1,flag&&i==num[p],i!=6);
}
return dp[p][flag2]=res;
}
int work(int x)
{
memset(dp,-1,sizeof(dp));
int len=0;
while(x)
{
num[len++]=x%10;
x/=10;
}
return dfs(len-1,1,1);
}
int main()
{
int n,m;
while(cin>>n>>m)
{
if(n==0&&m==0)
break;
printf("%d\n",work(m)-work(n-1));
}
return 0;
}
4.题目链接:hdu3555
【题意】跟上面一题差不多,求[1,x]中含49的有多少个
【思路】同样水题,记录前一个数字是不是4
/*************************************************************************
> File Name: hdu3555.cpp
> Author: wanghao
> Mail: [email protected]
> Created Time: 2015年07月06日 星期一 16时27分38秒
************************************************************************/
#include
#include
#include
#define ull unsigned long long
#define ll long long
using namespace std;
int num[25];
ll A[20];
long long dp[25][2];
long long dfs(int p,int flag,int flag4,int ok)
{
// cout<
5.题目链接:poj3252
【题意】将数化为二进制,0的个数不比1少,求[l,r]中这样的数有多少
【思路】将数转化为2进制,再进行dp,保存当前0,1的个数,注意开头取0的情况
/*************************************************************************
> File Name: poj3252.cpp
> Author: wanghao
> Mail: [email protected]
> Created Time: 2015年07月06日 星期一 19时23分03秒
************************************************************************/
#include
#include
#include
using namespace std;
int dp[35][35][35][2];
int num[35];
int dfs(int p,int num0,int num1,int flag)
{
// cout<=num1;
if(dp[p][num0][num1][flag]!=-1)
return dp[p][num0][num1][flag];
int u=flag?num[p]:1;
int res=0;
for(int i=0;i<=u;i++)
{
res+=dfs(p-1,num1?num0+!i:0,num1+i,flag&&i==num[p]);
}
// cout<<"ans "<=0;j--)
// cout<
【题意】取一个数中的某一数字为支点,左右距离*数字之和相等即为平衡数,例如4139,取3为支点,4*2+1*1=9*1,4139为平衡数求[l,r]间有多少个平衡数
【思路】对于一个数,若其为平衡数,则平衡点必唯一。设取x 点为支点,左侧加权和为Lx,数字和为SUMl;右侧加权和为Rx,数字和为SUMr.该数字为N x,则支点右移一位左侧加权和为Lx+SUMl+Nx,右侧加权和为Rx-SUMr。
观察原左右侧加权和之差,Lx-Rx,现加权和之差,Lx-Rx-(SUMl+Nx+SUMr)=Lx-Rx-sum(所有数字之和)。
发现,对于每一个支点,求得的差都是不一样的,因此平衡点必唯一。若存在平衡点,则Lx-Rx=0,取任意一点为支点,差值必然是sum的倍数!若差值为sum的倍数则必然存在平衡点,最左侧为支点差值<=0,最右侧为支点差值>=0,中间必有平衡点!以最右侧为支点,算出的差值为sum的倍数则该数是平衡数
/*************************************************************************
> File Name: hdu3709.cpp
> Author: wanghao
> Mail: [email protected]
> Created Time: 2015年07月06日 星期一 20时07分21秒
************************************************************************/
#include
#include
#include
#define ll long long
using namespace std;
int num[25];
ll dp[2000][180][20];
ll dfs(int p,int value,int sum,int flag)
{
//cout<>t;
while(t--)
{
long long a,b;
cin>>a>>b;
if(a>b)
{
int tm=b;
b=a;
a=tm;
}
cout<
【题意】数中出现13,[1,n]中有多少个这样的数
【思路】。。。
/*************************************************************************
> File Name: hdu3652.cpp
> Author: wanghao
> Mail: [email protected]
> Created Time: 2015年07月07日 星期二 00时18分32秒
************************************************************************/
#include
#include
#include
using namespace std;
int num[15];
int dp[12][13][2][2];
int dfs(int p,int yu,int flag1,int flag13,int flag)
{
if(p==-1)
return yu==0&&flag13;
if(!flag&&dp[p][yu][flag1][flag13]!=-1)//flag13也可单列出来,减小一维
return dp[p][yu][flag1][flag13];
int u=flag?num[p]:9;
int res=0;
for(int i=0;i<=u;i++)
{
res+=dfs(p-1,(yu*10+i)%13,i==1,flag13||(flag1&&i==3),flag&&i==num[p]);
}
// cout<
【题意】函数 F(x) = A n * 2 n-1 + A n-1 * 2 n-2 + ... + A 2 * 2 + A 1 * 1求[0,b]中f(i)比f(A)小的个数。
【思路】f最大为9*2^9.....+9*2^0=9*(2^10-1)<10*2^10,dp[len][sum]表示剩下长度为len,f值比sum小或相等的个数。奇怪的题目。。。
/*************************************************************************
> File Name: hdu4734.cpp
> Author: wanghao
> Mail: [email protected]
> Created Time: 2015年07月07日 星期二 00时18分32秒
************************************************************************/
#include
#include
#include
using namespace std;
int num[12];
int dp[12][5120];
int fa;
int f(int x)
{
int res=0;
int v=1;
while(x)
{
res=res+x%10*v;
x/=10;
v*=2;
}
return res;
}
int A[10];
int dfs(int p,int sum,int flag)
{
// cout<=0;
if(sum<0)
return 0;
if(!flag&&dp[p][sum]!=-1)
return dp[p][sum];
int u=flag?num[p]:9;
int res=0;
for(int i=0;i<=u;i++)
{
res+=dfs(p-1,sum-i*A[p],flag&&i==num[p]);
}
// cout<
9.题目链接:hdu4507
【思路】主要还是推平方和的公式 ∑(x+ai)^2=n*x^2+2*x*∑ai+∑ai^2,需要得到子问题的和及平方和及个数。细节地方一定要注意,个数为0与和为0是不一样的,和为0还有可能存在符合条件的数。求个数的时候一定要注意不要取模。。然而取模居然也能AC。。
/*************************************************************************
> File Name: hdu4507.cpp
> Author: wanghao
> Mail: [email protected]
> Created Time: 2015年07月07日 星期二 20时07分53秒
************************************************************************/
#include
#include
#include
#define ll long long
using namespace std;
int mod=1000000007;
ll dp[20][7][7][3];
ll A[20];
int num[20];
void dfs(int p,int sum7,int value7,int flag,ll *sum,ll *sum2,ll *sumn)
{
if(p==-1)
{
*sum=*sum2=0;
if(sum7==0||value7==0)
*sumn=0;
else *sumn=1;
return ;
}
if(!flag&&dp[p][sum7][value7][2]!=-1)
{
*sum=dp[p][sum7][value7][0];
*sum2=dp[p][sum7][value7][1];
*sumn=dp[p][sum7][value7][2];
return ;
}
int u=flag?num[p]:9;
*sumn=*sum=*sum2=0;
int ok=0;
for(int i=0;i<=u;i++)
{
if(i==7)continue;
ll a,b,c;
dfs(p-1,(sum7+i)%7,(value7*10+i)%7,flag&&i==num[p],&a,&b,&c);
if(c==0)//不判也能ac...但不知道为毛
continue;
ok=1;
*sum2=(*sum2+c%mod*i*A[p]%mod*i*A[p]%mod+b+2*i*A[p]%mod*a%mod)%mod;
*sum=(*sum +c%mod*i*A[p]+a)%mod;
*sumn=*sumn+c;//别取模。。但取模也能a
}
// cout<<"df "<>a>>b;
cout<<(work(b)-work(a-1)+mod)%mod<<'\n';
}
return 0;
}