BZOJ4602: [Sdoi2016]齿轮 DFS 逆元
这道题就是一个DFS,有一篇奶牛题几乎一样。但是这道题卡精度。
这道题网上的另一篇题解是有问题的。取对数这种方法可以被轻松卡。比如1e18 与 (1e9-1)*(1e9+1)取对数根本无法保证不被卡精度。所以我们需要换一个方法。
我们取一个大质数,在这个质数的模意义下进行运算:乘法是乘法,除法变成乘逆元,负数加一个质数。这种方法虽然可能冲突,但是与数据无关。
#include<cstdio> using namespace std ; struct edge { int p ; int a ; int b ; edge * next ; } ; const int p = 10079 ; int pow ( int a , int n ) { int ans = 1 ; while ( n ) { if ( n & 1 ) ans *= a , ans %= p ; a *= a ; a %= p ; n /= 2 ; } return ans ; } int inv ( const int a ) { return pow ( a , p - 2 ) ; } const int MAXN = 1234 ; const int MAXM = 12345 ; int N , M ; edge E [ MAXM * 2 ] ; edge * V [ MAXN ] ; bool vis [ MAXN ] ; int dis [ MAXN ] ; void read () { scanf ( "%d%d" , & N , & M ) ; for ( int i = 1 ; i <= N ; ++ i ) vis [ i ] = V [ i ] = 0 ; while ( M -- ) { int s , t , a , b ; scanf ( "%d%d%d%d" , & s , & t , & a , & b ) ; edge * const t1= & E [ M * 2 ] ; t1 -> p = t ; t1 -> a = a ; t1-> b = b < 0 ? b + p : b ; t1-> next = V [ s ] ; V [ s ] = t1 ; edge * const f = & E [ M * 2 + 1 ] ; f -> p = s ; f -> a = b < 0 ? b + p : b ; f -> b = a ; f -> next = V [ t ] ; V [ t ] = f ; } } bool dfs ( const int o ) { vis [ o ] = true ; for ( edge * v = V [ o ] ; v ; v = v -> next ) if ( ! vis [ v -> p ] ) { dis [ v -> p ] = dis [ o ] * v -> a % p * inv ( v -> b ) % p ; if ( ! dfs ( v -> p ) ) return false ; } else if ( dis [ v -> p ] != dis [ o ] * v -> a % p * inv ( v -> b ) % p ) return false ; return true ; } bool solve () { for ( int i = 1 ; i <= N ; ++ i ) if ( ! vis [ i ] && ( dis [ i ] = 1 , ! dfs ( i ) ) ) return false ; return true ; } int main () { int T ; scanf ( "%d" , & T ) ; for ( int i = 1 ; i <= T ; ++ i ) { read () ; printf ( "Case #%d: " , i ) ; puts ( solve () ? "Yes" : "No" ) ; } return 0 ; }