您的位置:首页 > 其它

zoj 3644(关于最小公倍数的DP)

2012-10-16 21:18 405 查看
这个题目必须得记录一下,经典。

dp【i】【j】 i表示现在在哪个点,j表示现在是第几个约数,记忆化搜索即可,做了一些题之后,发现这是个经典的设置状态方法。

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<map>
#define MOD 1000000007
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
#define LL long long
using namespace std;
const int maxn = 20005;
struct edge
{
int u,v,next;
}e[maxn];
map<LL,int> mp;
int n,m,K,dp[2005][1005];
int head[2005],tot,get[2005];
void add_edge(int u,int v);
int dfs(int now,LL x);
void init();
LL gcd(LL a,LL b){
return b==0?a:gcd(b,a%b);
}//最大公约数
LL lcm(LL a,LL b){
return a/gcd(a,b)*b;
}//最小公倍数
int main()
{
int i;
while(scanf("%d%d%d",&n,&m,&K) != EOF)
{
memset(dp,-1,sizeof(dp));
memset(head,-1,sizeof(head));
tot = 0;
for(i = 0;i < m;i ++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v);
}
for(i = 1;i <= n;i ++) scanf("%d",&get[i]);
init();
if(mp.find(get[1]) == mp.end())
{
printf("0\n");
continue;
}
printf("%d\n",dfs(1,get[1]));
}
return 0;
}
void add_edge(int u,int v)
{
e[tot].u = u,e[tot].v = v;
e[tot].next = head[u],head[u] = tot ++;
}
void init()
{
int i,j,cnt = 0;
mp.clear();
for(i = 1;i <= sqrt(K);i ++)
{
if(K % i) continue;
mp[i] = cnt ++;
mp[K / i] = cnt ++;
}
}
int dfs(int now,LL x)
{
if(dp[now][mp[x]] != -1) return dp[now][mp[x]];
if(now == n)
{
if(x == K)  return dp[now][mp[x]] = 1;
else return dp[now][mp[x]] = 0;
}
int i,sum = 0;
map<LL,int>:: iterator it;
for(i = head[now];i != -1;i = e[i].next)
{
int v = e[i].v;
LL y = lcm(x,get[v]);
if(y == x) continue;
it = mp.find(y);
if(it == mp.end()) continue;
sum += dfs(v,y);
sum %= MOD;
}
return dp[now][mp[x]] = sum;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: