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;
}

浙公网安备 33010602011771号