題意:從n*m網格圖的左下角走到右上角(n,m<=10^10),有t個座標不能經過(t<=200),只能向上向右走,問有多少種不同的走法,對p取模,
p只有兩種取值,1000003(質數)和1019663265(四個質數的乘積, 3*5*6793*10007)
考試的時候有部分分…
1. n,m<=1000時,o(nm)dp即可
2.t=0的時候求乙個組合數就可以了,1000003:預處理階乘及逆元,l1019663265:lucas定理求組合數之後用crt合併.
那麼考慮t=1的情況,我們只需要把總的路徑條數減去經過那個障礙點的路徑條數就可以了.走法=」左下角到障礙點的走法」*」障礙點到右上角的做法」
t=2時,設兩個障礙點為a,b,」總的路徑條數」-「經過a的路徑條數」-「經過b的路徑條數」算出來的答案可能偏小,如果a,b可以同時經過,那麼最終答案要加上」同時經過a,b的路徑條數」
那麼這道題就可以用容斥來做.方便起見給障礙點從左到右從下到上排個序,記f[i][j]表示走到了第i個障礙點且包括第i個點在內經過了j個障礙點的路徑條數,列舉從左下角的哪乙個點k走過來即可.轉移的時候乘上乙個組合數表示從k到i的走法數目.
注意迴圈的時候在最內層列舉j只需要o(n^2)次計算組合數,最內層列舉k需要計算o(n^3)次組合數,效率相差很大.我一開始在別的地方卡了半天常數終於在bz上卡進總時限了,但加了這個優化瞬間從10s+變成2s以內…**裡有很多卡常的痕跡,其實我在考試的時候連wys那個鬼畜的迴圈展開都用了然而組合數計算次數太多了還是沒卡過去...
#include#includeusing
namespace
std;
typedef
long
long
ll;ll n,m;
intt,mod;
int quickpow(int a,int
x)
return
ans;
}namespace
prime
}intc(ll n,ll m)
int lucas(ll n,ll m)
};namespace
notprime;
int fac[4][maxn],inv[4
][maxn];
int buf3[4][4]=,,,};
int buf5[6][6]=,,,,};
void
init()}}
intm;
int lucas(ll n,ll m,int
t)
int t1=n/m,t2=m/m;
return lucas(t1,t2,t)*lucas(n-t1*1ll*m,m-t2*1ll*m,t)%m;
}int res[4
];
intcrt()
return
ans;
}};namespace
ending
bool
operator
<(const point &b)const
}p[205];
void dp(int
q) }
}int lim=t+1
;
for(int k=0;k<=t;++k)
f[lim][k]=tmp%m;
}int ans=0
;
for(int k=0;k<=t;++k)
res[q]=ans;
}};int
main()
p[0].x=0;p[0].y=0;p[t+1].x=n;p[t+1].y=m;p[t+1].sum=n+m;
sort(p+1,p+t+1
);
if(mod==1000003
) }
}for(int k=0;k<=t;++k)
}int ans=0
;
for(int k=0;k<=t;++k)
printf(
"%d\n
",ans);
}else
//fclose(stdin);fclose(stdout);
return0;
}
BZOJ3782 上學路線
bzoj 第一行,四個整數 n,m,t,p 接下來的 t 行,每行兩個整數,表示施工的路口的座標。一行,乙個整數,路徑數 mod p 的值。3 4 3 1019663265 3 01 1 2 28 1 le n,m le 10 0 le t le 200 p 1000003 或 p 10196632...
安徽上學路線
思路 跑spfa 網路流最小割。跑正反兩邊spfa,然後拎出一條邊,判斷邊權 左端點到1號節點的最短路 右端點到n號節點的最短路 離1號節點近的點為左端點,反之為右端點 是否等於1到n的最短路,如果相等左右端點連邊,權值為這條邊代價。然後跑dinic。分析 真是桑心!這道題切了乙個晚上,最後在rc ...
BZOJ 1266 上學路線route(最小割)
題意 給出乙個無向圖,每條邊有長度和代價。求出1到n的最短路。之後刪掉一些邊使得1到n的最短路變大?在此情況下使得刪掉邊的代價之和最小。思路 首先求出每個點到1和n的最短路。之後可以確定每條邊是否為關鍵邊 就是最短路上的邊 將關鍵邊建立網路流圖,求最小割即可。struct node node edg...