2020hdu多校第六場比賽及補題
1009Divisibility
題意搞半天才搞懂,把一個詞翻譯了一下,原來是命題的意思,我以為是一個定義。。
還是隊友告訴我我才理解的題意
就是一個命題:如果任意一個b進位制數,如果它的每位數加起來能被 x 整除,那麼它也可以被 x 整除
就比如任意一個10進位制數,如果它的每一位數加起來能被 3 整除,那麼它就能被 3 整除,命題為真
但任意一個10進位制數,如果它的每一位數加起來能被4整除,它不一定能被4整除,命題就為假
為什麼b=10時,x=3時,會有這個性質呢
這是因為10≡1(mod3),100≡1(mod3),1000≡1(mod3)....,46374≡(40000+6000+300+70+4)≡(4+6+3+7+4) (mod3)
(這個原理我很早以前就知道的)
顯而易見,就是任意一個數左移一位後要同餘它本身,左移一位就相當於乘以b,也就是要滿足b≡1(mod x)
#include<iostream> #include<algorithm> using namespace std; int main() { int T; long long b,x; cin>>T; while(T--){ cin>>b>>x; if((b-1)%x==0) cout<<"T"<<endl; else cout<<"F"<<endl; } return 0; }
1002Little Rabbit's Equation
進位制模擬題,感覺有點麻煩的模擬,還好隊友幫我過了這題,強
#include <bits/stdc++.h> using namespace std; #define int long long // const int MAXN = ; // const int MOD = ; // const int INF = ; // const double eps = ; // const int DIRX[] = {}; // const int DIRY[] = {}; string str; char op; string num[5]; int dci[5]; void getnum() { int cnt = 1; num[1] = ""; num[2] = ""; num[3] = ""; for (int i = 0; i < str.length(); ++i) { if (str[i] == '=') { cnt++; continue; } else if (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/') { cnt++; op = str[i]; continue; } else { if (str[i] >= '0' && str[i] <= '9') num[cnt] += (char)(str[i] - '0' + 1); else num[cnt] += (char)(str[i] - 'A' + 11); } } if (op == '-') { op = '+'; swap(num[1], num[3]); } if (op == '/') { op = '*'; swap(num[1], num[3]); } } int32_t main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); while (cin >> str) { getnum(); bool flg = false; for (int i = 2; i <= 16; ++i) { bool ok = false; for (int j = 1; j <= 3; ++j) { dci[j] = 0; int tmp = 1; for (int k = num[j].length() - 1; k >= 0; --k) { // cout << (int)num[j][k] << " "; if (num[j][k] - 1 >= i) { ok = true; break; } dci[j] += (num[j][k] - 1) * tmp; tmp *= i; } if (ok) break; } // cout << dci[1] << " " << dci[2] << " " << dci[3] << endl; if (ok) continue; if (!ok && op == '+') { if (dci[1] + dci[2] == dci[3]) { flg = true; // cout << dci[1] << "+" << dci[2] << "=" << dci[3] << endl; cout << i << endl; } } if (!ok && op == '*') { if (dci[1] * dci[2] == dci[3]) { flg = true; // cout << dci[1] << "*" << dci[2] << "=" << dci[3] << endl; cout << i << endl; } } if (flg) break; } if (!flg) cout << -1 << endl; } return 0; }
1001Road To The 3rd Building
有 n 個數,要在[1,n]裡任選一個區間,區間的價值=區間內所有數之和 / 區間長度,求價值的期望是多少
思路:求每個數對最終價值的期望的貢獻
假設有五個數,
若選擇的區間長度為5,這五個數各自貢獻的區間數為 1 1 1 1 1
若選擇的區間長度為4,這五個數各自貢獻的區間數為 1 2 2 2 1
若選擇的區間長度為3,這五個數各自貢獻的區間數為 1 2 3 2 1
若選擇的區間長度為2,這五個數各自貢獻的區間數為 1 2 2 2 1
若選擇的區間長度為1,這五個數各自貢獻的區間數為 1 1 1 1 1
就是這個規律
#include<iostream> #include<algorithm> #include<cstdio> using namespace std; const int MAXN = 2e5+7; const long long MOD = 1e9+7; long long s[MAXN]; long long th[MAXN]; long long inv[MAXN]; long long qpow(long long n,long long p){ long long ret = 1; for (; p; p >>= 1, n = n * n % MOD) if (p & 1) ret = ret * n % MOD; return ret; } long long mod_inv(long long a) { return qpow(a,MOD - 2); } void pre(){ inv[1] = 1; for (int i = 2; i <= 2e5; ++i) inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD; for(int i = 1;i <= 2e5; i++){ th[i] = (th[i-1] + inv[i]) % MOD; } } int main() { int T, n; pre(); cin >> T; while(T--){ cin >> n; for(int i = 1;i <= n;i++){ scanf("%lld",&s[i]); } long long fz = 0, fm; long long tt = 0; for(int i = 1;i * 2 <= n;i++){ s[i] += s[n-i+1]; s[i] %= MOD; tt += th[n-i+1] - th[i-1]; tt = (tt % MOD + MOD) % MOD; fz = (fz + s[i] * tt) % MOD; } if(n % 2){ tt += inv[n/2+1]; tt = (tt % MOD + MOD) % MOD; fz = (fz + s[n/2+1] * tt) % MOD; } fm = (long long)n * ((long long)n+1) / 2 % MOD;//n沒有強制轉換成long long啊啊 long long ans = fz * mod_inv(fm) % MOD; cout<<ans<<endl; } return 0; }
n沒有強制轉換成long long wa了挺久qwq
1006A Very Easy Graph Problem
給n個點,m條邊,每個點有0,1兩種狀態,要求所有0點到所有1點的最短路的長度之和
給的這m條邊滿足第 i 條邊的長度為2^i
根據邊長度的性質,可以知道如果A點連了長度為2,4,8,16的邊到B,又連了條直接從A到B的邊,但這邊的長度為32,不能為最短路
推出一個結論,後面加的邊不可能更新已有的最短路,這個邊就忽略掉
這樣就像一個並查集一樣,把這個圖變成若干棵樹,然後我就在這些樹上進行樹形dp
然後我寫了個dfs就MLE了...
直到比賽結束我還是MLE
現在才發現原來我並查集寫炸了,死迴圈了。。。。
然後並查集改好了,還是wa了,手推樣例才發現,我那樹形dp的方法是錯的,要直接dfs一遍每條邊的貢獻就是這條邊的長度*(其一端0點數*另一端1點數+另一端0點數*其一端1點數)
終於過了xd
#include<iostream> #include<algorithm> #include<cstdio> #include<vector> using namespace std; const int MAXN = 1e5+7; const int MAXM = 2e5+7; const long long MOD = 1e9+7; int a[MAXN]; long long llo[MAXM]; struct EDGE{ int to, w ,next; }edge[MAXN*2]; int head[MAXN],tot; void add(int u,int v,int w){ tot++; edge[tot].to = v; edge[tot].w = w; edge[tot].next = head[u]; head[u] = tot; } int n,m; long long ans; int par[MAXN]; int find(int x){ if(par[x] == x) return x; return par[x] = find(par[x]); } void pre(){ llo[0] = 1; for(int i = 1;i <= 2e5;i++){ llo[i] = llo[i-1] << 1; llo[i] %= MOD; } } int son0[MAXN],son1[MAXN]; long long edg[MAXN]; void dfs(int st,int f){ son0[st] = son1[st] = 0; if(a[st] == 0) son0[st]++; else son1[st]++; for(int i = head[st];i ;i = edge[i].next){ int po = edge[i].to; if(po == f) continue; long long lo = edge[i].w; lo = llo[lo]; edg[po] = lo; dfs(po,st); son0[st] += son0[po]; son1[st] += son1[po]; } } int main() { //freopen("1.in","r",stdin); int T; pre(); cin >> T; int u,v; while(T--){ cin >> n >> m; ans = 0; tot = 0; for(int i = 1;i <= n; i++) { scanf("%d",&a[i]); par[i] = i; head[i] = 0; } for(int i = 1;i <= m; i++) { scanf("%d%d",&u,&v); int fu = find(u), fv = find(v); if(fu == fv) continue; else{ par[fu] = fv; add(u,v,i); add(v,u,i); } } long long res; for(int i = 1;i <= n;i++){ if(par[i] == i) dfs(i,0); } for(int i = 1;i <= n;i++){ if(find(i)!=i){//不能寫成if(par[i]!-=i)因為par[i]並不一定直接連到根節點! long long ct = 0; ct = (long long)son1[i] * ( (long long)son0[par[i]] - (long long)son0[i] ) + (long long)son0[i] * ( (long long)son1[par[i]] - (long long)son1[i] ) ; ans += edg[i] * ct; ans %= MOD; } } cout << ans << endl; } return 0; }