SCAU 2019年校賽 部分題解
點選下方 veiw code 檢視完整程式碼
18438 First Blood
題意:\(\sum_{i=1}^a\)\(\sum_{j=1}^b\)(i+j) , 求和。
思路:簽到題,照著題目A就行了。
view code
#include<iostream> #include<string> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> #include<map> #include <queue> #include<sstream> #include <stack> #include <set> #include <bitset> #include<vector> #define FAST ios::sync_with_stdio(false) #define abs(a) ((a)>=0?(a):-(a)) #define sz(x) ((int)(x).size()) #define all(x) (x).begin(),(x).end() #define mem(a,b) memset(a,b,sizeof(a)) #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define rep(i,a,n) for(int i=a;i<=n;++i) #define per(i,n,a) for(int i=n;i>=a;--i) #define pb push_back #define mp make_pair #define fi first #define se second using namespace std; typedef long long ll; typedef pair<ll,ll> PII; const int maxn = 3e4+2; const int inf=0x3f3f3f3f; const double eps = 1e-7; const double pi=acos(-1.0); const int mod = 1e9+7; inline int lowbit(int x){return x&(-x);} ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d); inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;} inline ll inv(ll x,ll p){return qpow(x,p-2,p);} inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;} inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();return x*f; } int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} }; int main() { int kase; cin>>kase; while(kase--) { ll a,b; cin>>a>>b; ll ans = 0; rep(i,1,a) rep(j,1,b) ans += i+j; cout<<ans<<endl; } return 0; }
18429 Earning Money for Dating
題意:有兩個工作,每個工作需要耗時一小時,都需要做m次,同時每個工作有冷卻時間,CD分別是t\({_0}\)和t\({_1}\)。問最小需要多長時間才能把兩件工作做完(各m次)。
1.想要天數儘量少,那就儘量讓CD長的在等待的時候把另一個工作完成儘量多一點。
2.不妨設t\({_0}\) > t\({_1}\)。 則t\({_0}\)-1就是我們要來填充的間隙,-1是因為Job0工作就要1個小時。
現在,如果t\({_0}\)-1的時間內能讓Job1完成當前的,同時開始下一次,那麼最長時間只取決於Job0(腦補一下為什麼),此時的答案就是t\({_0}\)
但是當t\({_0}\) - t\({_1}\) <= 1的時候,Job1在t\({_0}\)-1間隙裡完成一輪工作加休息後想開始新工作時會和Job0衝突。什麼意思? 如t\({_0}\) = 5, t\({_1}\) = 4, Job1在t\({_0}\)-1完成一輪,這個時候Job1和Job0開始工作的時刻重合了。這樣就需要在上面討論的結果裡多加一個1,即t\({_0}\)
3.最後討論一下t1和t0同時為1的情況,這個時候是直接2m。
view code
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
#include<sstream>
#include <stack>
#include <set>
#include <bitset>
#include<vector>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 1e6+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){return x&(-x);}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();return x*f; }
int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
int main()
{
ll kase;
cin>>kase;
while(kase--)
{
ll m;
cin>>m;
ll t0, t1; cin>>t0>>t1;
if(t0==0) t0 = 1; if(t1==0) t1 = 1;
if(t0<t1) swap(t0,t1);
if(m==1)
{
cout<<2<<endl;
continue;
}
if(t0==1&&t1==1) //都為1就只能2m
cout<<2*m<<endl;
else //開始時刻衝突就多+1
{
if(t0-t1<=1) cout<<t0*(m-1) + 2<<endl;
else cout<<t0*(m-1) + 1<<endl;
}
}
return 0;
}
18430 Aerial Photography
題意:有n個點,從原點出發,每次可以最多走M個單位距離,不夠的時候又可以回原點重新獲得M次單位的距離(返航也要消耗M),問最少返航多少次可以走完n個點。
資料量小,直接暴力。(138ms AC)
1.先預處理一下座標。給n個點兩兩建邊。
2.dfs列舉每個點,當前這個點無非有兩種走法,一種是飛到一個除自身和原點以外的點、一個是飛回原點補充能量
3.那麼,針對上述兩種情況,我要使得每個點都有這兩種選擇,那就必須到的每個點都有“退路”,就是你到這個點的時候要保證還有能量回原點苟。即判斷條件是當前剩餘Left - D[x][y] - D[y][0] >=0 ,表示當前剩餘的能量夠飛到y點且y點還能飛回原點。
4.然後什麼時候要飛回原點呢?你要是能量夠的話,完全沒必要回去。為什麼?你如果能量夠回原點一趟再去別的點y,那為什麼不直接飛去點y呢?所以只有當沒有點可以飛的時候才要回原點
5.然後遞迴出口就是飛滿了n個點。最後肯定是停在第n個點的。而我們的條件限制又使得每次可以夠能量回原點。所以最後走完n個點就直接可以 ans = min(ans.cur)了。
view code
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
#include<sstream>
#include <stack>
#include <set>
#include <bitset>
#include<vector>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 3e4+2;
const ll inf= 1e18;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){return x&(-x);}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();return x*f; }
int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
typedef struct Pos
{
ll x;
ll y;
} P;
P a[150];
ll vis[150];
ll n,m;
double D[50][50];
ll ans = inf;
ll cur = 1;
void dfs(ll x, double Left, ll num)
{
if(cur>ans) return;
if(num==n)
{
ans = min(cur,ans);
return;
}
bool flag = false;
for(int i=0;i<=n; ++i)
{
ll v = i; double cost = D[x][i];
if(vis[v]||v==0||v==x) continue;
if(Left-cost-D[v][0]>=0)
{
flag = true;
vis[x] = 1;
dfs(v,Left-cost,num+1);
vis[x] = 0;
}
}
if(!flag)
{
cur++;
vis[x] = 1;
dfs(0,m,num);
cur--;
vis[x] = 0;
}
}
int main()
{
ll kase;
kase = read();
while(kase--)
{
mem(vis,0); ans = inf; cur = 1;
n = read(); m = read(); mem(D,0);
if(n==0)
{
cout<<0<<'\n';
continue;
}
rep(i,1,n) a[i].x = read(), a[i].y = read();
a[0].x = a[0].y = 0;
rep(i,1,n) rep(j,0,i-1)
{
double dis =sqrt ( (a[i].x-a[j].x)*(a[i].x-a[j].x) + (a[i].y-a[j].y)*(a[i].y-a[j].y) );
D[i][j] = D[j][i] = dis;
}
dfs(0LL,m,0);
cout<<ans<<endl;
}
return 0;
}
18434 Painting Walls
題意:題意:給一個序列若干詢問,每次詢問對m個區間計數+1,求最後計數等於k的區間元素和。
思路:差分和雜湊
1.首先發現,題目簡化後的邏輯表達就是每次詢問讓你給區間【L,R】內的值+1,然後每次詢問完回答該操作完後有哪些區間被覆蓋了k次,輸出對應區間和
2.對於區間加和問題,可能會往線段樹或者樹狀陣列的方向想,但是這個題明確是每次+1,就相當於區間的計數,所以可以往差分的方向想。
3.構建差分陣列b[i] = a[i] - a[i-1],它有什麼特點呢?一個是差分陣列的i位置字首和就是對應a[i](自行證明),另一個就是本題關鍵——我要讓【L,R】區間內的值+1,只需要b[L]++, b[R+1]--即可。(為什麼?就相當於這個區間內部差分不變,因為是同時+1。而對於區間左邊界相當於比前一個數多了一,右邊界比後一個數少1)。
4.然後,用map存這些區間端點(自帶按照鍵大小排序),這個時候我們只需要遍歷一遍這些詢問到的端點,用變數cur += b[i],表示當前區間的詢問次數。
比如:詢問【1,10】,【3,5】。通過上述知道
b[1] = 1 , b[3] = 1 , b[6] = -1, b[11] = -1,
假設本次詢問 k=2 . 那麼在遍歷一遍詢問到的區間端點時,
1).cur += b[1] => 1
2).cur += b[3] => 2 注意,此時cur等於k,說明這個點開始的區間已經滿足題意了。但我們現在不知道這個區間多長,就先標記著 flag = 1
3).cur += b[6] => 1 哦吼,發現cur變了,這個時候我們就知道前面滿足題意的區間是多長了,就是i - pre(前一個端點)+ 1 。這個時候答案就是ans += sum[i-1] - sum[pre-1]。同時flag=0
4).cur += b[11] => 0 發現沒啥玩意了。不計數。
5.主體思路便是如上。最後注意一個非常噁心的點。k可以取0,這個時候要反過來求!
view code
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
#include<sstream>
#include <stack>
#include <set>
#include <bitset>
#include<vector>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 1e6+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){return x&(-x);}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();return x*f; }
int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
ll b[maxn];
ll a[maxn];
ll sum[maxn];
map<ll,ll> Map;
int main()
{
// freopen("DATA.txt","r",stdin);
ll kase;
kase = read();
while(kase--)
{
ll n,d;
n = read(); d = read(); rep(i,0,n) sum[i] = 0;
rep(i,1,n) a[i] = read(), sum[i] = sum[i-1] + a[i];
rep(i,1,d)
{
Map.clear();
ll m, k;
m = read(); k = read();
if(k)
{
rep(j,1,m)
{
ll L, R;
L = read(); R = read();
b[L] ++ , b[R+1] --;
Map[L] = Map[R+1] = 1;
}
ll cur = 0; ll pre = 1; ll ans = 0; bool flag = 0;
for(map<ll,ll>:: iterator it = Map.begin(); it!=Map.end();it++)
{
cur += b[it->fi];
if(flag) ans += sum[it->fi-1] - sum[pre-1];
if(cur==k)
flag = 1;
else flag = 0;
pre = it->fi;
}
printf("%lld\n",ans);
for(map<ll,ll>:: iterator it = Map.begin(); it!=Map.end();it++) b[it->fi] = 0;
}
else
{
rep(j,1,m)
{
ll L, R;
L = read(); R = read();
b[L] ++ , b[R+1] --;
Map[L] = Map[R+1] = 1;
}
ll cur = 0; ll pre = 1; ll ans = 0; bool flag = 0;
for(map<ll,ll>:: iterator it = Map.begin(); it!=Map.end();it++)
{
cur += b[it->fi];
if(flag) ans += sum[it->fi-1] - sum[pre-1];
if(cur)
flag = 1;
else flag = 0;
pre = it->fi;
}
ans = sum[n] - sum[0] - ans;
printf("%lld\n",ans);
for(map<ll,ll>:: iterator it = Map.begin(); it!=Map.end();it++) b[it->fi] = 0;
}
}
}
return 0;
}
18435 This is Not Bug, But Feature
題意:給一個字串,若出現“bug”子串的次數超過1次,就把多出來的替換成“feature”。
小模擬題,flag標記是否為第一次出現。多出來的部分替換即可。可以用string容器簡化步驟,詳見程式碼。
view code
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
#include<sstream>
#include <stack>
#include <set>
#include <bitset>
#include<vector>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 3e4+2;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){return x&(-x);}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();return x*f; }
int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
string s;
char nxt[3] = {'b', 'u', 'g' };
bool check(int pos)
{
char cur = 0;
for(int i=pos;i<min(s.size(), pos+3);i++)
{
if(cur==3) return true;
if(nxt[cur]==s[i])
cur++;
else return false;
}
if(cur==3) return true;
return false;
}
int main()
{
int kase = 10;
while(kase--)
{
getline(cin,s); int flag = 0;
for(int i=0;i<s.size();i++)
{
if(check(i))
{
if(!flag)
flag = 1;
else
{
string t1(s,0,i);
string t2(s,i+3,s.size()-i-2);
string t3 = "feature";
t1 = t1+t3;
t1 = t1 + t2;
s = t1;
i += 6;
}
}
}
cout<<s<<endl;
}
return 0;
}
18436 Path
題意:給一個圖。每條邊有兩個權值A,B。問1->n的路徑中\({SumA\over SumB}\)的最小值。
這個題有一點技巧性。。。
思路如下:
1.首先,如果往最短路的方向想的話可以收收了,不然會和我一樣前期陷進死衚衕。
2.我們發現,這個題要求SumA/SumB最小,而不是求路徑和最小,這說明了什麼?我們可以重複走一條邊任意多次!有什麼用呢?比如我們發現有兩點之間的SumA/SumB是整個圖裡面最小的(而且在1->n路徑上),那麼我們就可以把這兩點的之間的邊來回走無限多次,這樣的效果是什麼,取極限來看,這樣整個的和就無限接近於 (ksumA)/(ksumB) = sumA/sumB。其中k->正無窮。這樣,問題就變成了,只要我找到兩點之間的suma/sumb是最小的,通過走這個路徑無限次,答案就一定會取到它。比如1->2->3的路徑,n=3時,若1->2的A/B是1/2,而2->3的A/B是1/10,那我們就把2->3這條邊反覆橫條無限多次,這樣前面那個1/2就可以忽略不計,答案既然是1/10。
3.第二步仔細理解一下。然後我們就來到第三個問題,這兩個點怎麼找呢?
我先說結論,最小值肯定是在相鄰的兩個點中產生的。
比如1->2->3->4->5,我們要找的兩個點的不會找13之間或者14之間或者24之間這樣的。為什麼?
其實是個數學問題,假設\({A1\over B1}\) < \({A2\over B2}\) , 那麼一定有\({A1+A2\over B1+B2}\)> \({A1\over B1}\) ,最小值還是A1/B1所在的那條邊(證明的話兩個不等式各自交叉相乘一下會發現是一樣的)。所以,最小值一定在相鄰的點中產生。
4.那問題越來越簡單了,我們只需要找到最A/B最小的一條邊即可。但是最後有一點要注意除了結點1和結點n是保證聯通的,其他點不一定和1->n的路徑上的點聯通。所以這裡要用一個並查集維護一下。一條邊上的兩個點同時和1和n聯通才能選。
5.最後求最簡式只需要上下除個最大公約數即可。
view code
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
#include<sstream>
#include <stack>
#include <set>
#include <bitset>
#include<vector>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 4e4+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){return x&(-x);}
int gcd(int a,int b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline int read(){ int f = 1; int x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0', ch = getchar();return x*f; }
int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
const int V = 5005, E = 55500;
int head[V], nxt[E], pnt[E], e = 1;
double costa[E], costb[E];
int Map[maxn];
int fa[maxn];
int n,m;
void addedge(int x, int y, int A, int B)
{
pnt[e] = y;
costa[e] = (double)A;
costb[e] = (double)B;
nxt[e] = head[x];
head[x] = e++;
}
int get(int x)
{
if(fa[x]==x) return x;
return fa[x] = get(fa[x]);
}
void merge(int x, int y)
{
int fx = get(x);
int fy = get(y);
if(fx!=fy) fa[fx] = fa[fy];
}
void init()
{
rep(i,0,n+1) fa[i] = i,head[i] = 0;
e = 1;
}
int main()
{
int kase;
cin>>kase;
while(kase--)
{
n = read(), m = read();
init();
rep(i,1,m)
{
int x = read(), y = read();
int A = read(), B = read();
merge(x,y);
addedge(x,y,A,B);
addedge(y,x,A,B);
}
int ansA=1e12, ansB=1;
rep(i,1,n)
{
for(int j=head[i]; j; j = nxt[j])
{
int v = pnt[j];
if(get(v)==get(1)&&get(v)==get(n))
{
if((double)ansA/ansB > costa[j]/costb[j])
{
ansA = costa[j];
ansB = costb[j];
}
}
}
}
int d = gcd(ansA,ansB);
ansA /= d, ansB /= d;
printf("%d/%d\n",ansA,ansB);
}
return 0;
}