NKOJ3882 统计
时间限制 : - MS 空间限制 : 165536 KB
评测说明 : 1s
问题描述
找出n位数中位数积为k的数的个数,包括前导0
输入格式
n、k
输出格式
一个整数,表示个数
输入样例1:
2 3
输出样例1:
2
输入样例2:
2 0
输出样例2:
19
提示
对于 20% :N <= 6。
对于 50 %:N<=16
存在另外 30%:K=0 。
对于 100%:N <= 50,0 <= K <=10^90。
思路:
首先要发现是高精度……
对于k=0的情况,特盼
对于k!=0,f[n][k]=sum(f[n-1][k/i]) (i能整除k)
采用记忆化搜索,用map映射n、k,大整数类不方便存储进map,开vector,映射下标。
#include<cstdio>
#include<iostream>
#include<vector>
#include<map>
using namespace std;
int n,k;
//.......................................
struct zz
{
vector<short> s;
zz(){};
zz operator= (int b)
{
s.clear();
if(b==0) {s.push_back(0);return *this;}
while(b) s.push_back(b%10),b/=10;
return *this;
}
zz operator+ (const zz &b)
{
zz ans;
int la=s.size(),lb=b.s.size(),len=max(la,lb);
int w=0;
for(int i=0;i<len;i++)
{
if(i<la) w+=s[i];
if(i<lb) w+=b.s[i];
ans.s.push_back(w%10);
w/=10;
}
while(w) ans.s.push_back(w%10),w/=10;
return ans;
}
zz operator * (const long long & b) const
{
zz ans;
long long w=0;
for(int i=0,size=s.size();i<size;i++)
{
w+=s[i]*b;
ans.s.push_back(w%10);
w/=10;
}
while(w) ans.s.push_back(w%10),w/=10;
return ans;
}
friend ostream& operator<<(ostream& out,const zz & a)
{
for(int i=a.s.size()-1;i>=0;i--) out<<a.s[i];
return out;
}
};
//.......................................
typedef pair<int,int> pii;
map<pii,int> ma;
vector<zz> v;int tot=1;
int newzz(zz &ans)
{
v.push_back(ans);
return ++tot;
}
int f(int x,int k)
{
pii xx=make_pair(x,k);
if(ma.find(xx)!=ma.end()) return ma[xx];
if(x==1) return ma[xx]=newzz(k>9 ? v[0] :v[1]);
int t=k,pos=9,cnt=0;
while(t>1)//剪枝
{
while(true)
{
if(t%pos!=0) pos--;
else break;
if(pos==1&&t>1) return ma[xx]=0;//如果k不能表示为1~9的乘积,则没有方案
}
t/=pos;
cnt++;//cnt表示k在1~9之间的最小因数个数
}
if(cnt>x) return ma[xx]=0;//若x位比能填的因数最小还要小,则没有方案
zz ans;ans=0;
for(int i=1;i<=9;i++)
{
if(k%i==0) ans=ans+v[f(x-1,k/i)];
}
return ma[xx]=newzz(ans);
}
int main()
{
scanf("%d%d",&n,&k);
if(k==0)
{
zz ans,temp;
ans=0;
for(int i=1,j;i<=n;i++)
{
temp=1;
for(j=1;j<i;j++) temp=temp*9;
for(j=i+1;j<=n;j++) temp.s.insert(temp.s.begin(),0);
ans=ans+temp;
}
cout<<ans;
return 0;
}
v.resize(2);
v[0]=0,v[1]=1;//0、1在后面需要使用,先加进去
ma[make_pair(0,1)]=1;
cout<<v[f(n,k)];
}