LeetCode——遞增的三元子序列
阿新 • • 發佈:2020-08-09
AEFIK
A. Groundhog and 2-Power Representation
題意
一個數可以由2x1+2x2+2x3+.....組成,例如1315=210+28+25+2+1=2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0). 現在給出一個由2的次冪組成的表示式,輸出這個數是多少。題解
不得不說py真的強,看到不到2分鐘就有人a了,還以為是原題,賽後發現py三行。(暴風哭泣 我隊用的c++高精度模擬寫的,隊友%%%程式碼
py1 n = input() 2 n = n.replace("(","**(") 3 print(eval(n))
c++
1 #include<bits/stdc++.h> 2 #define pb push_back 3 using namespace std; 4 typedef long long ll; 5 const int inf = 0x3f3f3f3f; 6 const ll INF = 0x3f3f3f3f3f3f3f3f; 7 const int maxn = 3e4+10; 8 9 vector<int> mult(vector<int>x,vector<int>y)//高精*高精View Code10 { 11 int xlen=(int)x.size(),ylen=(int)y.size(),zlen=xlen+ylen; 12 vector<int>z(zlen); 13 for(register int i=0;i<xlen;i++) 14 for(register int j=0;j<ylen;j++) 15 z[i+j]+=x[i]*y[j]; 16 for(register int i=0;i<zlen;i++) 17 if(z[i]>9)18 { 19 z[i+1]+=z[i]/10; 20 z[i]%=10; 21 } 22 while(zlen>1 && !z.back()) 23 { 24 z.pop_back(); 25 zlen--; 26 } 27 return z; 28 } 29 vector<int> chu(int x,vector<int> vv) 30 { 31 bool flag=false; 32 vector<int> ans; 33 int t=0; 34 int i; 35 for (i=vv.size()-1; i>=0; i-- ) 36 { 37 t=t*10+vv[i]; 38 if(flag) 39 { 40 ans.push_back(t/x); 41 } 42 else if(t/x>0) 43 { 44 flag=true; 45 ans.push_back(t/x); 46 } 47 t=t%x; 48 } 49 return vector<int> (ans.rbegin(),ans.rend()); 50 } 51 vector<int> add(vector<int>x,vector<int>y)//高精+高精 52 { 53 int xlen=(int)x.size(),ylen=(int)y.size(),zlen=max(xlen,ylen)+1; 54 vector<int>z(zlen); 55 for(register int i=0;i<zlen;i++) 56 { 57 if(i<xlen) 58 z[i]+=x[i]; 59 if(i<ylen) 60 z[i]+=y[i]; 61 if(z[i]>9) 62 { 63 z[i+1]++; 64 z[i]-=10; 65 } 66 } 67 while(zlen>1 && !z.back()) 68 { 69 zlen--; 70 z.pop_back(); 71 } 72 return z; 73 } 74 void prin(vector<int> x) 75 { 76 int i; 77 if(x.size() == 0) 78 { 79 printf("0"); 80 } 81 for (i=x.size()-1;i>=0;i--) 82 { 83 printf("%d",x[i]); 84 } 85 printf("\n"); 86 } 87 std::vector<int> qup(std::vector<int> vv) 88 { 89 std::vector<int> ans; 90 ans.pb(1); 91 std::vector<int> v; 92 std::vector<int> f; 93 f.pb(0); 94 v.pb(2); 95 while(vv.size() > 0 && *(--vv.end()) != 0) 96 { 97 if(vv[0] & 1) 98 ans = mult(v,ans); 99 vv = chu(2,vv); 100 v = mult(v,v); 101 } 102 return ans; 103 } 104 105 char a[maxn]; 106 vector<int> dg(int l,int r) 107 { 108 vector<int> ans; 109 110 if(l == r) 111 { 112 ans.pb(a[l] - '0'); 113 return ans; 114 } 115 ans.pb(0); 116 std::vector<int> temp; 117 for (int i = l; i <= r; i ++ ) 118 { 119 120 if(a[i] == '(') 121 { 122 int s= 0 ; 123 for(int j = i + 1; j <= r; j ++ ) 124 { 125 if(a[j] == '(') 126 s ++ ; 127 if(a[j] == ')') 128 { 129 if(s == 0) 130 { 131 ans = add(ans,qup(dg(i + 1, j - 1))); 132 i = j; 133 break; 134 } 135 else 136 s -- ; 137 } 138 } 139 continue; 140 } 141 if(a[i] == '+') 142 { 143 ans = add(ans,dg(i + 1,r)); 144 break; 145 } 146 else 147 { 148 if(a[i + 1] != '(') 149 { 150 temp.pb(a[i] - '0'); 151 ans = add(ans,temp); 152 } 153 continue; 154 } 155 } 156 return ans; 157 } 158 159 int main() 160 { 161 scanf("%s",a + 1); 162 int n = strlen(a + 1); 163 vector<int> ans = dg(1,n); 164 prin(ans); 165 }
E. Groundhog Chasing Death
題意
給出a,b,c,d,x,y,求\displaystyle\prod_{i=a}^b\prod_{j=c}^d\gcd(x^i,y^j)i=a∏bj=c∏dgcd(xi,yj) modulo 998244353的結果題解
第一想法肯定是暴力:列舉 i 和 j ,然後算出每一個 gcd(xi,yj),然後乘起來。但是資料 i 和 j 的資料範圍都在1e6,這樣肯定會超時,i 和 j 的範圍在1e9,這樣肯定是要爆long long的。那麼就要想想怎麼優化。 因為這是一個乘性函式,那麼肯定要想到分解質因子,所以先預處理 x 的質因子,並記錄每個質因子出現的次數,這樣 xi就可以由每個質因子個數再 *i 得到。列舉 xi中因子 m 出現的次數,可以發現當 yj小的時候,gcd(xi,yj) 主要是被 yj的 m 個數約束,此時是一個等差數列;當yj大的時候,就是由xi約束,此時 yj中 m 的個數是一個常數,暴力求解就好了。 由於質因子的冪很大,會爆long long,所以要用尤拉降冪,尤拉降冪是對mod-1取模(隊友對mod取模debug好久程式碼
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 const ll mod = 998244353; 6 const ll md = 998244352; 7 vector<pair<ll,ll> > v; 8 9 void div(ll n) 10 { 11 v.clear(); 12 ll k = sqrt(n); 13 for (ll i = 2; i <= k; ++ i) { 14 ll cnt = 0; 15 while (n % i == 0) { 16 n /= i; 17 cnt ++; 18 } 19 v.push_back({i, cnt}); 20 } 21 if (n != 1) { 22 v.push_back({n, 1}); 23 } 24 } 25 26 ll phi(ll n) 27 { 28 ll ans = n; 29 ll k = sqrt(n); 30 for (int i = 2; i <= k; ++i) { 31 if (n % i == 0) { 32 ans = ans / i * (i - 1); 33 while (n % i == 0) n /= i; 34 } 35 } 36 if (n > 1) { 37 ans = ans / n * (n - 1); 38 } 39 return ans; 40 } 41 42 ll pow(ll a, ll b, ll p) { 43 ll res = 1; 44 while (b) { 45 if (b & 1) res = (res * a) % p; 46 a = a * a % p; 47 b >>= 1; 48 } 49 return res%p; 50 } 51 52 int main() 53 { 54 ll a, b, c, d, x, y; 55 scanf("%lld%lld%lld%lld%lld%lld", &a, &b, &c, &d, &x, &y); 56 a = max(1LL, a); 57 c = max(1LL, c); 58 --c; 59 div(x); 60 ll ans = 1; 61 for (int i = 0; i < (int)v.size(); ++ i) { 62 ll cnt = 0; 63 while (y % v[i].first == 0) { 64 y /= v[i].first; 65 ++ cnt; 66 } 67 ll sum = 0; 68 if (cnt == 0) continue; 69 for (ll j = a; j <= b; ++ j) { 70 ll e = v[i].second * (ll)j; 71 ll f = e/cnt; 72 while (cnt * f < e) { 73 ++ f; 74 } 75 if (c >= f) { 76 sum -= ((f * (f-1) / 2)% md * (cnt % md)) % md; 77 sum = (sum % md + md) % md; 78 sum -= (ll)(((c-f+1) % md) * (e % md)) % md; 79 sum = (sum % md + md) % md; 80 } 81 else { 82 sum -= ((c * (c+1) / 2) % md * (cnt % md)) % md; 83 sum = (sum % md + md) % md; 84 } 85 sum = (sum % md + md) % md; 86 if (d >= f) { 87 sum += ((f * (f-1) / 2) % md) * (cnt % md) % md; 88 sum = (sum % md + md) % md; 89 sum += (ll)(((d-f+1) % md) * (e % md)) % md; 90 sum = (sum % md + md) % md; 91 } 92 else { 93 sum += (((d * (d+1) /2) % md) * (cnt) % md) % md; 94 sum = (sum % md + md) % md; 95 } 96 } 97 sum = (sum % md + md) % md; 98 ans *= pow(v[i].first, sum, mod); 99 ans = (ans % mod + mod) % mod; 100 } 101 ans = (ans % mod + mod) % mod; 102 printf("%lld\n", ans); 103 return 0; 104 }View Code
F.Groundhog Looking Dowdy
題意
土撥鼠要和蘋果約會,第 i 天它的第 j 件衣服的邋遢度為 aij,它要在n天中選擇m天和蘋果約會,要求選出的m天衣服的邋遢度的最大值和最小值的差值最小。題解
因為要最小化最大值和最小值的差值,所以用pair存每件衣服的邋遢度和第幾天,然後對邋遢度從小到大排序。那麼問題就轉換成了求一個區間 [L,R] ,使得這個區間覆蓋m個不同的天,並且R的邋遢度-L的邋遢度最小。這個問題就可以用尺取解決了。對於每一個L,求出最小的合法的R,每次更新差值最小值即可。程式碼
1 #include<bits/stdc++.h> 2 #define st first 3 #define sd second 4 #define ll long long 5 #define pii pair<int,int> 6 using namespace std; 7 8 const int inf = 0x3f3f3f3f; 9 const int maxn = 2e6+10; 10 11 pii pp[maxn]; 12 int vis[maxn]; 13 14 int main() 15 { 16 int n,m; 17 scanf("%d%d",&n,&m); 18 int cnt = 0; 19 for (int i = 1; i <= n; i ++ ){ 20 int p; 21 scanf("%d",&p); 22 for (int j = 1; j <= p; j ++ ){ 23 int x; 24 scanf("%d",&x); 25 pp[++cnt].st = x; 26 pp[cnt].sd = i; 27 } 28 } 29 sort(pp + 1, pp + 1 + cnt); 30 int num = 0; 31 int l = 1, r = 1; 32 int minn = pp[1].st, maxx = 0; 33 int ans = inf; 34 while(1){ 35 while(r <= cnt && num < m){ 36 if(vis[pp[r].sd] == 0) num ++ ; 37 vis[pp[r].sd] ++ ; 38 maxx = pp[r].st; 39 r ++ ; 40 } 41 if(num < m) 42 break; 43 ans = min(ans, maxx - minn); 44 vis[pp[l].sd] -- ; 45 if(vis[pp[l].sd] == 0) num -- ; 46 minn = pp[l + 1].sd; 47 l ++ ; 48 } 49 printf("%d\n",ans); 50 }View Code
I.The Crime-solving Plan of Groundhog
題意
給出n個數(0<=a[i]<=9),由這n個數組成2個數,使得這兩個數的乘積最小。題解
自己造幾個例子就可以看出,選擇0之外最小的數和剩下的數字組成的沒有前導0的數相乘結果最小。剩下的數字怎樣最小呢,當然是找到最小的非零的數做第一位,後邊接上所有的0,再按照有小到大的順序放剩下的數字。因為n的範圍在1e5,所以要用高精度乘法。推導:
把當前的數字拆成4個數 a, b, c, d (a ≤ b ≤ c ≤ d) ,那麼我們有兩種決策:兩位數×兩位數,或者三位數×一 位數。 (10a + d) * (10b + c) = 100ab + 10ac + 10bd + cd (100b+10c+d) * a = 100ab + 10ac +ad<(10a + d) * (10b + c) 同理,可以證明留一個最小的正整數作為第一個數,剩下的所有數字排成最小的數作為第二個數時,答案取到最小值。程式碼
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 5 int a[100100]; 6 7 int main() 8 { 9 ios::sync_with_stdio(false); 10 cin.tie(0); 11 cout.tie(0); 12 int t; 13 cin>>t; 14 while(t--){ 15 int n; 16 cin>>n; 17 for(int i=0;i<n;i++) cin>>a[i]; 18 sort(a,a+n); 19 int k=0; 20 while(k<n&&a[k]==0) k++; 21 vector<int>q; 22 q.push_back(a[k+1]); 23 for(int i=0;i<k;i++) q.push_back(0); 24 for(int i=k+2;i<n;i++) q.push_back(a[i]); 25 vector<int>ans; 26 for(int i=q.size()-1;i>=0;i--){ 27 int x=q[i]*a[k]; 28 ans.push_back(x); 29 } 30 for(int i=0;i<10;i++) ans.push_back(0); 31 for(int i=0;i<ans.size();i++){ 32 if(ans[i]>=10){ 33 ans[i+1]+=ans[i]/10; 34 ans[i]%=10; 35 } 36 } 37 while(!ans.back()) ans.pop_back(); 38 for(int i=ans.size()-1;i>=0;i--) cout<<ans[i]; 39 cout<<endl; 40 } 41 return 0; 42 }View Code
K.The Flee Plan of Groundhog
題意
土撥鼠在第1個宿舍,橙子在第n個宿舍。這n個宿舍間有n-1條路並且長度都為1,土撥鼠從第1個房間去第n個宿舍,速度為1m/s;橙子從第n個宿舍追趕土撥鼠,速度為2m/s。題解
二分時間 t ,然後判斷在 ts 內土撥鼠是否會被橙子追上。以橙子所在的寢室 n 為根建樹,從 1 到 n 列舉所有土撥鼠能夠到達的點,先找出t秒能走到哪個點,然後再找這個點能走到的離n最遠的點,判斷在走的過程中會不會被追上。程式碼
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 1e5+10; 5 vector<int> vv[maxn]; 6 int vis[maxn]; 7 int f[maxn]; 8 int dep[maxn]; 9 10 void dfs(int x,int fa,int de) 11 { 12 f[x] = fa; 13 dep[x] = de; 14 for (int i =0 ; i< vv[x].size(); i ++ ) 15 { 16 int v = vv[x][i]; 17 if(v == fa) 18 continue; 19 dfs(v,x,de + 1); 20 vis[x] |= vis[v]; 21 } 22 } 23 int ans =0 ; 24 void dfs2(int x,int fa,int de) 25 { 26 ans = max(ans,de); 27 for (int i =0 ; i<vv[x].size(); i ++ ) 28 { 29 int v = vv[x][i]; 30 if(v == fa) 31 continue; 32 dfs2(v,x,de + 1); 33 } 34 35 } 36 int main() 37 { 38 int n,m; 39 scanf("%d%d",&n,&m); 40 for (int i = 1; i < n; i ++ ) 41 { 42 int x,y; 43 scanf("%d%d",&x,&y); 44 vv[x].push_back(y); 45 vv[y].push_back(x); 46 } 47 vis[1] = 1; 48 dfs(n,0,1); 49 int k = -1; 50 int s = dep[1] - m; 51 for (int i = 1; i <= n; i ++ ){ 52 if(vis[i] && dep[i] == s){ 53 k = i; 54 break; 55 } 56 } 57 int num = dep[k] - 1; 58 dfs2(k,f[k],1); 59 ans -- ; 60 num += ans; 61 int r = (num + 1) / 2; 62 int l = 0; 63 while(l < r){ 64 int mid = l + r>> 1; 65 int x = min(2 * mid,num); 66 int y = min(mid, ans); 67 if(x - dep[k] + 1>= y) r = mid; 68 else l = mid + 1; 69 } 70 printf("%d\n",l); 71 }View Code