[题解] Luogu P6381 『MdOI R2』Odyssey

https://www.luogu.com.cn/problem/P6381

一个不怎么要脑子的做法...代码也不难写...

考虑在DAG上DP

\(f_{i,j}\)表示以点\(i\)为结尾,且上一条边权值为\(j\)的最长路径数量。

那么有转移

\(f_{v,b} = \max \{ f_{u,a} + l \}\)\(ab=c^k\)且存在边\((u,v,w)\)

先不管这样做的空间...

考虑如何做到转移时满足\(ab = c^k\)这个条件

\(a\)质因数分解:\(a = p_1^{e_1}\cdots p_s^{e_s}\)

然后将所以指数对\(k\)取模,即令\(e'_i = e_i \bmod k\)

然后得到一个数\(a' = p_1^{e'_1} \cdots p_s ^{e'_s}\)

\(b' = p_1^{k-e'_1} \cdots p_s ^{k-e'_s}\)

即对于\(b\)质因数分解后也做这样的操作可以得到\(b'\)

同时对于\(a\),与之匹配的\(b\)做这个操作后得到的\(b'\)是唯一的,这也非常方便算出来。

那么状态变一变,改成\(f_{i,j'}\),即以\(i\)结尾,上一条边做上述变换后得到的数为\(j'\)时的最长路径。

但数太大了,数组开不下,而且直接把数带进去也不好算

注意到一个数的质因子个数不会太多,我们可以把他的质因数分解作为第二维(指数对\(k\)取模后的)然后DP。

不想hash的话开个map记一下状态好了,DP就直接按拓扑序去转移

具体还是看代码吧...

跑的超慢的\(Code\):

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef pair<int,int> pii;
typedef vector<pii> pfac;
pfac factor(int n,int k)
{
    pfac ans;
    for(int i=2;i*i<=n;i++)
    {
        int cnt=0;
        while(n%i==0) (++cnt)>=k?cnt-=k:0,n/=i;
        if(cnt) ans.pb(mp(i,cnt));
    }
    if(n>1&&k!=1) ans.pb(mp(n,1));
    return ans;
}
pfac mpfac(const pfac &pf,int k)
{
    pfac ans;
    for (auto p:pf) ans.pb(mp(p.fi,k-p.se));
    return ans;
}
const int N=1111111;
int n,m,k;
struct edge
{
    int u,v,w,l,nxt;
    pfac pf;
}e[N];
int fst[N],ec=0,ind[N],ans=0;
void ade(int u,int v,int w,int l)
{
    e[++ec]=(edge){u,v,w,l};
    e[ec].pf=factor(w,k);
    e[ec].nxt=fst[u],fst[u]=ec;
    ++ind[v];
    ans=max(ans,l);
}
int tps[N],tn;
void topo()
{
    tn=0;
    queue<int> q;
    for(int i=1;i<=n;i++) if(ind[i]==0) q.push(i);
    while(q.size())
    {
        int u=q.front(); q.pop();
        tps[++tn]=u;
        for(int i=fst[u];i;i=e[i].nxt)
        {
            int v=e[i].v; --ind[v];
            if (ind[v]==0) q.push(v);
        }
    }
}
map<pfac,int> f[N];
void dp()
{
    for(int i=1;i<=tn;i++)
    {
        int u=tps[i];
        for(int j=fst[u];j;j=e[j].nxt)
        {
            int v=e[j].v;
            pfac pf=e[j].pf,mpf=mpfac(pf,k);
            f[v][mpf]=max(f[v][mpf],f[u][pf]+e[j].l);
            ans=max(ans,f[v][mpf]);
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1,u,v,w,l;i<=m;i++)
        scanf("%d%d%d%d",&u,&v,&w,&l),ade(u,v,w,l);
    topo(),dp();
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wxq1229/p/12939317.html
今日推荐