team2012-F3-sol-0001
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
{{{
题意:给定一个有向图,每个节点一个权值。从起点出发,每到一个节点分数变为当前分数和节点权值的最小公倍数,且分数不能不变,问走到最后一个节点且分数是k的方案数。
解法:设F[i][s]为走到第i个节点,分数为s的方案数,则通过有向图上的边(i,j)可以转移到F[j][S],且S>s。不过由于k太大,无法直接表示。
考虑每次都变为当前分数和节点权值的最小公倍数,即每次分数变为整数倍,且最后分数为k,所以中间所有可行状态的分数均为k的因子
只记录这些状态即可,状态数变为n*sqrt(k)。
}}}
{{{
#include <iostream>
#include <vector>
#include <map>
#include <cstring>
using namespace std;
typedef long long LL;
const int MOD = 1000000007;
int n, m, k, p[2002];
int f[2002][2002];
vector<int> conn[2002];
vector<int> fact;
map<int, LL> num_fact;
LL gcd(LL a, LL b)
{
while(b)
{
LL c = a % b;
a = b;
b = c;
}
return a;
}
LL lcm(LL a, LL b)
{
return a / gcd(a, b) * b;
}
int main()
{
while(cin>>n>>m>>k)
{
for(int i=1;i<=n;i++)
conn[i].clear();
for(int i=1;i<=m;i++)
{
int a, b;
cin>>a>>b;
conn[a].push_back(b);
}
for(int i=1;i<=n;i++)
cin>>p[i];
fact.clear();
num_fact.clear();
for(int i=1;i<=k;i++)
if(k%i==0)
{
num_fact[i] = fact.size();
fact.push_back(i);
}
if(num_fact.count(p[1]) == 0)
{
cout<<0<<endl;
continue;
}
int st = num_fact[p[1]];
memset(f, 0, sizeof(f));
f[1][st] = 1;
for(int i=st;i<fact.size();i++)
{
int fact_now = fact[i];
for(int j=1;j<=n;j++)
if(f[j][i])
{
for(int k=0;k<conn[j].size();k++)
{
int v = conn[j][k];
LL next_fact = lcm(p[v], fact_now);
if(num_fact.count(next_fact) && next_fact != fact_now)
{
f[v][num_fact[next_fact]] += f[j][i];
f[v][num_fact[next_fact]] %= MOD;
}
}
}
}
cout<<f[n][num_fact[k]]<<endl;
}
return 0;
}
}}}
题意:给定一个有向图,每个节点一个权值。从起点出发,每到一个节点分数变为当前分数和节点权值的最小公倍数,且分数不能不变,问走到最后一个节点且分数是k的方案数。
解法:设F[i][s]为走到第i个节点,分数为s的方案数,则通过有向图上的边(i,j)可以转移到F[j][S],且S>s。不过由于k太大,无法直接表示。
考虑每次都变为当前分数和节点权值的最小公倍数,即每次分数变为整数倍,且最后分数为k,所以中间所有可行状态的分数均为k的因子
只记录这些状态即可,状态数变为n*sqrt(k)。
#include <iostream>
#include <vector>
#include <map>
#include <cstring>
using namespace std;
typedef long long LL;
const int MOD = 1000000007;
int n, m, k, p[2002];
int f[2002][2002];
vector<int> conn[2002];
vector<int> fact;
map<int, LL> num_fact;
LL gcd(LL a, LL b)
{
while(b)
{
LL c = a % b;
a = b;
b = c;
}
return a;
}
LL lcm(LL a, LL b)
{
return a / gcd(a, b) * b;
}
int main()
{
while(cin>>n>>m>>k)
{
for(int i=1;i<=n;i++)
conn[i].clear();
for(int i=1;i<=m;i++)
{
int a, b;
cin>>a>>b;
conn[a].push_back(b);
}
for(int i=1;i<=n;i++)
cin>>p[i];
fact.clear();
num_fact.clear();
for(int i=1;i<=k;i++)
if(k%i==0)
{
num_fact[i] = fact.size();
fact.push_back(i);
}
if(num_fact.count(p[1]) == 0)
{
cout<<0<<endl;
continue;
}
int st = num_fact[p[1]];
memset(f, 0, sizeof(f));
f[1][st] = 1;
for(int i=st;i<fact.size();i++)
{
int fact_now = fact[i];
for(int j=1;j<=n;j++)
if(f[j][i])
{
for(int k=0;k<conn[j].size();k++)
{
int v = conn[j][k];
LL next_fact = lcm(p[v], fact_now);
if(num_fact.count(next_fact) && next_fact != fact_now)
{
f[v][num_fact[next_fact]] += f[j][i];
f[v][num_fact[next_fact]] %= MOD;
}
}
}
}
cout<<f[n][num_fact[k]]<<endl;
}
return 0;
}