P12742 [POI 2016 R3] 信使 Messenger Solution

在 Print 之前

容斥是个好东西,但我不会。

荣登次劣解。

思路

考虑到起点和终点只计算一次,所以可以枚举起点和终点,然后把他们从点集中删掉,这样我们只需要考虑从一个起点到其他点的方案数。

具体的,定义 \(dis_{i,j,k}\) 表示当前经过 \(k\) 条边,起点在 \(i\),终点在 \(j\) 的方案数。

转移和答案的计算是显然的,记录 \(st\) 表示当前要求的步数,答案就应该是:

\[ans_{s,t,st} = \sum _{x \in son_s} \sum _{x \in son_t} dis_{x,y,st-2} \]

因为每次求 \(dis_{i,j,k}\) 是 \(O(m \max (st))\),所以现在的复杂度是 \(O(n^3 m \max (st))\) 的,考虑到起点之间的答案互不影响,所以可以视作多个起点,这样代码就是 \(O(n^2 m \max (st))\),因为 \(\max (st) \le 50\),所以 10s 实现轻松通过。

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstring>
#ifdef _WIN32
#define getchar _getchar_nolock
#define putchar _putchar_nolock
#else
#define getchar getchar_unlocked
#define putchar putchar_unlocked
#endif
#define pll pair<ll,ll>
#define pld pair<ld,ld>
typedef int ll;
typedef long double ld;
typedef __int128 i128;
namespace io {
    using namespace std;
    template <typename T> void debug (T x) {
        cerr<<x<<'\n';
    }
    template <typename T> void debuglen (T x) {
        cerr<<x<<' ';
    }
    template <typename T,typename...Args> void debug (T x,Args...args) {
        debuglen(x);
        debug(args...);
    }
    template <typename T> void debug (T *lt,T *rt) {
        ll len=rt-lt;
        for (ll i=0;i<len;i++) {
            debuglen(*(lt+i));
        }
        cerr<<'\n';
    }
    inline ll read () {
        char x=getchar();
        ll ans=0,f=1;
        while (x<'0'||x>'9') {
            if (x=='-') {
                f=-1;
            }
            x=getchar();
        }
        while (x>='0'&&x<='9') {
            ans=(ans<<1)+(ans<<3);
            ans+=(x^'0');
            x=getchar();
        }
        return ans*f;
    }
    template <typename T> void write (T x) {
        if (x<0) {
            putchar('-');
            x=-x;
        }
        if (x>=10) {
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template <typename T> inline void print (T x) {
        write(x);
        putchar('\n');
    }
    template <typename T> inline void printlen (T x) {
        write(x);
        putchar(' ');
    }
    template <typename T,typename...Args> inline void print (T x,Args...args) {
        printlen(x);
        print(args...);
    }
    template <typename T> inline void print (T *lt,T *rt) {
        ll len=rt-lt;
        for (ll i=0;i<len;i++) {
            if (i==len-1) {
                print(*(lt+i));
                return ;
            }
            printlen(*(lt+i));
        }
    }
}
using namespace io;
const ll N=1e2+5,inf=2e9;
const ld eps=1e-6;
ll n,m,mod,ans[N][N][51],dis[N][49],L,R;
bool vis[N][51];
vector<ll> v[N];
pll q[N*50];
inline void calc (ll s,ll t) {
    for (ll i=1;i<=n;i++) {
        for (ll j=0;j<=48;j++) {
            dis[i][j]=0;
            vis[i][j]=0;
        }
    }
    L=R=0;
    for (ll i=0;i<v[s].size();i++) {
    	ll it=v[s][i];
        if (it==t) {
            continue;
        }
        dis[it][0]=1;
        q[++R]={it,0};
    }
    while (L<R) {
        L++;
        ll d=q[L].first,op=q[L].second;
        ll val=dis[d][op];
        if (!val) {
            continue;
        }
        for (ll i=0;i<v[d].size();i++) {
    		ll it=v[d][i];
            if (it==s) {
                continue;
            }
            if (it==t) {
            	ans[s][t][op+2]+=val;
                if (ans[s][t][op+2]>=mod) {
                    ans[s][t][op+2]-=mod;
                }
            	continue;
			}
            dis[it][op+1]+=val;
            if (dis[it][op+1]>=mod) {
                dis[it][op+1]-=mod;
            }
            if (!vis[it][op+1]&&op!=48) {
                q[++R]={it,op+1};
                vis[it][op+1]=1;
            }
        }
    }
}
inline void solve () {
    n=read(),m=read(),mod=read();
    for (ll i=1;i<=m;i++) {
        ll ul=read(),vl=read();
        ans[ul][vl][1]=1;
        v[ul].push_back(vl);
    }
    for (ll i=1;i<=n;i++) {
        for (ll j=1;j<=n;j++) {
            if (i==j) {
                continue;
            }
            calc(i,j);
        }
    }
    ll ql=read();
    while (ql--) {
        ll x=read(),y=read(),op=read();
        print(ans[x][y][op]);
    }
}
int main () {
    // freopen("messenger.in","r",stdin);
    // freopen("messenger.out","w",stdout);
    ll T=1;
    while (T--) {
        solve();
    }
    return 0;
}
posted @ 2026-10-13 21:50  Ptll  阅读(7)  评论(0)    收藏  举报