给出一个数n,根据该数建图,从每个点到该点的倍数(包括自己和0)连一条单向边
然后给出三个数,q1,q2,q3,求出
1.从1到q1所有长度为2的点
2.从1到0中长度小于q2的路径个数
3.从1到0中长度小于q3且不经过重复点的路径个数
4.3中所有路径上的编号和的和
这道题看上去是道数论题,实际上是dp题
对于第一问,我们可以发现,从1可以到任何数,而到q1的只能是q1的因数,所以直接暴力求因数个数,不讲了
对于第二问我们可以dp首先对于小于1000的数据可以暴力dp,更大的数据我们可以根据第三问的答案来求第二问。
假设我们知道了一条路径(不走重复点)
设路径上第i各节点在最后的路径上出现了xi次,那么就是x1+x2+x3+…+xk<=q2的正整数解个数,用组合数可以知道答案是 c(k,q2)
对于第三问,我们发现,从i走到的点只有i,2i,3i,…[n/i]i
然后我们对这些点重新标号为1,2,3,…[n/i],然后路径的条数是一样的!!!
唉,Hash_table使人愁
Code:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn = 2e5;
const int mod =1e9+7;
const int inv2 =5e8+4;
int n,q1,q2,q3,mxc;
int inv[233],C[233];
LL ans1,ans2,ans3,ans4;
void solve1(){
if(q1==0) ans1=n;
else{
int i;ans1=0;
for(i=1;i*i<q1;i++)
if(q1%i==0) ans1+=2;
if(i*i==q1) ans1++;
}
}
struct hash_table{
static const int mod=2333347;
int hash(int _key1,int _key2){
return (_key1+(_key2<<20))%mod;
}
int hd[mod],key1[maxn],key2[maxn],val3[maxn],val4[maxn],nxt[maxn],tl;
int insert(int _key1,int _key2,int _val3,int _val4){
int h=hash(_key1,_key2);
++tl;key1[tl]=_key1;key2[tl]=_key2;
val3[tl]=_val3;val4[tl]=_val4;
nxt[tl]=hd[h];hd[h]=tl;
return tl;
}
int findid(int _key1,int _key2){
int h=hash(_key1,_key2);
int cnt=1;
for(int i=hd[h];i;i=nxt[i],++cnt){
if(mxc<cnt) mxc=cnt;
if(key1[i]==_key1&&key2[i]==_key2)
return i;
}
return -1;
}
}dp;
int dfs(int n,int d){
int ret=dp.findid(n,d) ;
if(ret!=-1) return ret;//remember
if(d==1) return dp.insert(n,d,1,1) ;
if(n==1) return dp.insert(n,d,0,0) ;
int dp3=0,dp4=0;
for(int l=2,r=-1;l<=n;l=r+1){
int t=n/l;r=n/t;
int id=dfs(t,d-1);
dp3=(dp3+1LL*dp.val3[id]*(r-l+1))%mod;
dp4=(dp4+1LL*dp.val4[id]*(l+r)%mod*(r-l+1)%mod*inv2)%mod;
}
dp4+=dp3;if(dp4>=mod) dp4-=mod;
return dp.insert(n,d,dp3,dp4);
}
void solve34(){
for(int i=1;i<=q3&&i<=25;i++){
int id=dfs(n,i);//at position(n),len is i
ans3+=dp.val3[id];
ans4+=dp.val4[id];
}
ans3%=mod,ans4%=mod;
}
void solve2(){
inv[1]=C[0]=1;
for(int i=2;i<=25;i++)
inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=25;i++)
C[i]=1LL*C[i-1]*(q2-i+1)%mod*inv[i]%mod;
for(int i=1;i<=q2&&i<=25;i++){
int id=dfs(n,i);
ans2=(ans2+1LL*dp.val3[id]*C[i])%mod;
}
}
int main(){
scanf("%d%d%d%d",&n,&q1,&q2,&q3);
solve1(),solve34(),solve2();
printf("%lld %lld %lld %lld\n",ans1,ans2,ans3,ans4);
return 0;
}