[1547A]. Shortest Path with Obstacle
-
思路: F F F只有在 A , B A,B A,B两位置与坐标平行的直线距离之间时才会影响(距离 + 2 +2 +2)
#include<bits/stdc++.h> #define fora(i, a, b) for(int i = a; i <= b; i++) #define fors(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double using namespace std; int t, xa, ya, xb, yb, xf, yf, ans; int main(){ cin >> t; while(t--){ cin >> xa >> ya >> xb >> yb >> xf >> yf; ans = abs(xa - xb) + abs(ya - yb); if(xa == xb && xa == xf && min(ya, yb) < yf && yf < max(ya, yb)) ans += 2; if(ya == yb && ya == yf && min(xa, xb) < xf && xf < max(xa, xb)) ans += 2; cout << ans << endl; } }
[1547B]. Alphabetical Strings
-
思路:首先要判断没有重复,其次要判断按顺序出现(小的没出大的不能有)。最后查看能否成立,对于任意两个 j , i j,\,i j,i,以 a a a为中心原点有 ∣ j ∣ < ∣ i ∣ |j|<|i| ∣j∣<∣i∣时,只要保证 a [ j ] ≤ a [ i ] a[j]\le a[i] a[j]≤a[i]即可
#include<bits/stdc++.h> #define fora(i, a, b) for(int i = a; i <= b; i++) #define fors(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double using namespace std; int t, a[30], ls, no, v, flg[30]; string s; int main(){ cin >> t; while(t--){ cin >> s; ls = s.length(), no = 0; memset(flg, 0, sizeof(flg)); memset(a, 0, sizeof(a)); fora(i, 0, ls - 1){ if(flg[s[i] - 'a' + 1]) no = 1; //判断重复 else flg[s[i] - 'a' + 1] = 1; if(s[i] == 'a') v = i; } fora(i, 1, ls) if(!flg[i]) no = 1; //要求按顺序出现 fora(i, 0, ls - 1) a[s[i] - 'a' + 1] = i - v; fora(i, 1, ls) fora(j, 1, i - 1) if((0 < a[i] && a[i] < a[j]) || (a[i] < 0 && a[j] < a[i])) no = 1; cout << (no == 1 ? "NO" : "YES") << endl; } }
[1547C]. Pair Programming
-
思路:只有当选择数字大于 0 0 0时才有可能由于行数不够而出错,因此为了尽量在输入数字之前使更多的 0 0 0输入,且要保证按照 a , b a,b a,b数组的顺序输出,可以每次选择两个数组第一待选择中较小的那个数,最后再将还剩余的数组选入补齐。接着只需要判断数字大于 0 0 0时行数是否足够即可
#include<bits/stdc++.h> #define fora(i, a, b) for(int i = a; i <= b; i++) #define fors(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double using namespace std; int t, k, n, m, x, y, a[105], b[105], no; int main(){ cin >> t; while(t--){ cin >> k >> n >> m; queue<int> q, p; no = 0, x = 0, y = 0; fora(i, 1, n) cin >> a[i]; fora(i, 1, m) cin >> b[i]; while(x < n && y < m){ if(a[x + 1] <= b[y + 1]) q.push(a[++x]); //输入较小的 else q.push(b[++y]); } while(x < n) q.push(a[++x]); //补齐 while(y < m) q.push(b[++y]); //补齐 while(q.size()){ int tmp = q.front(); q.pop(); if(tmp > k) no = 1; //判断行数是否足够 if(tmp == 0) k++; if(no != 1) p.push(tmp); } if(no == 1) cout << -1 << endl; else{ while(p.size()){ cout << p.front() << " "; p.pop(); } cout << endl; } } }
[1547D]. Co-growing Sequence
-
思路:首先由式子 a i & a i + 1 = a i a_i\&a_{i+1}=a_i ai&ai+1=ai,对于每一位 a i + 1 a_{i+1} ai+1有( a i a_i ai为 1 1 1时 a i + 1 a_{i+1} ai+1必为 1 1 1)
a i a_i ai 0 0 1 1 a i + 1 a_{i+1} ai+1 0 1 1 1 记 a i − 1 = x i ⊕ y i a_{i-1} = x_i\oplus y_i ai−1=xi⊕yi当 a i − 1 a_{i-1} ai−1的 p p p位等于 1 1 1时: a i a_i ai的 p p p位等于 1 1 1,则 x i = 1 x_i=1 xi=1有 y i = 0 y_i=0 yi=0; x i = 0 x_i=0 xi=0有 y i = 1 y_i=1 yi=1;当 a i − 1 a_{i-1} ai−1的 p p p位等于 0 0 0时: a i a_i ai的 p p p位无限制,则 y i = 0 y_i=0 yi=0为理想情况(使字典序更小)。
a i − 1 a_{i-1} ai−1 0 0 1 1 a i a_i ai 0 1 1 1 x i x_i xi 1 0 1 0 y i y_i yi 1 0 0 1 故可以算出 y i = ( a i − 1 ∣ x i ) ⊕ x i y_i=(a_{i-1}|x_i)\oplus x_i yi=(ai−1∣xi)⊕xi
#include<bits/stdc++.h> #define fora(i, a, b) for(int i = a; i <= b; i++) #define fors(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double const int maxn = 2e5 + 5; using namespace std; int t, n; ll x[maxn], y[maxn]; int main(){ cin >> t; while(t--){ cin >> n; fora(i, 1, n) scanf("%d", &x[i]); memset(y, 0, sizeof(y)); cout << y[1] << " "; fora(i, 2, n){ y[i] = ((y[i - 1] ^ x[i - 1]) | x[i]) ^ x[i]; cout << y[i] << " "; } cout << endl; } }
[1547E]. Air Conditioners
-
思路:算是动态规划,对于每个屋子,先假设每个空调屋只对其后面的屋子有影响 d p [ i ] = m i n ( d p [ i − 1 ] + 1 , t [ i ] ) dp[i] = min(dp[i - 1] + 1, t[i]) dp[i]=min(dp[i−1]+1,t[i]),从最早的空调屋正向遍历一遍;再检查每个空调屋对其前面屋子的能否影响,使 d p [ i ] = m i n ( d p [ i ] , d p [ i + 1 ] + 1 ) dp[i] = min(dp[i], dp[i + 1] + 1) dp[i]=min(dp[i],dp[i+1]+1),反向遍历一遍。
#include<bits/stdc++.h> #define fora(i, a, b) for(int i = a; i <= b; i++) #define fors(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double const int INF = 0x7fffffff; const int maxn = 3e5 + 5; using namespace std; int q, n, k; ll minn, a[maxn], t[maxn], dp[maxn]; int main(){ cin >> q; while(q--){ cin >> n >> k; memset(t, 0, sizeof(t)); memset(dp, 0, sizeof(dp)); minn = INF; fora(i, 1, k){ scanf("%d", &a[i]); minn = min(minn, a[i]); //记录最早有空调的屋子 } fora(i, 1, k) scanf("%d", &t[a[i]]); dp[minn] = t[minn]; fora(i, minn + 1, n){ //正向遍历一遍,从最早有空调的屋子开始 if(t[i] > 0) dp[i] = min(dp[i - 1] + 1, t[i]); else dp[i] = dp[i - 1] + 1; } fors(i, n - 1, 1){ //反向遍历一遍 if(dp[i] > 0) dp[i] = min(dp[i], dp[i + 1] + 1); else dp[i] = dp[i + 1] + 1; } fora(i, 1, n) printf("%lld ", dp[i]); cout << endl; } }
[1547F]. Array Stabilization (GCD version)
-
思路:发现第 k k k次操作时 b i = gcd ( a i , a i + 1 , a i + 2 , . . . , a i + k ) b_i=\gcd(a_i,a_{i+1},a_{i+2},...,a_{i+k}) bi=gcd(ai,ai+1,ai+2,...,ai+k),而且最终操作结果使得数组所有数变为 c o m g c d comgcd comgcd(所有数的最大公约数)。
于是找到以 a [ i ] a[i] a[i]为开头的最短区间 g c d gcd gcd使其等于 c o m g c d comgcd comgcd,则此区间长度 p p p即为第 i i i个数需要的步骤。由于 p p p是唯一确定的且 p ∈ [ 0 , n ] p\in [0,n] p∈[0,n]单调,所以可以用二分查找来求 p p p;在计算区间 g c d gcd gcd时可以用 S T ST ST表使复杂度大幅降低。
-
详细思路推荐这位大佬
-
复杂度: O ( n log ( n log max { a [ i ] } ) ) O(n\log(n\log\max\{a[i]\})) O(nlog(nlogmax{a[i]}))
//复杂度O(n * log(n * log max(a[i]))) #include<bits/stdc++.h> #define fora(i, a, b) for(int i = a; i <= b; i++) #define fors(i, a, b) for(int i = a; i >= b; i--) #define ll long long #define db double const int INF = 0x7fffffff; const int maxn = 2e5 + 5; using namespace std; int t, n, a[2 * maxn], comgcd, st[2 * maxn][20], ans; int gcd(int a, int b){ return (b ? gcd(b, a % b) : a); } int main(){ cin >> t; while(t--){ memset(a, 0, sizeof(a)); ans = 0; cin >> n; comgcd = -1; fora(i, 1, n){ scanf("%d", &a[i]); a[i + n] = a[i]; comgcd = (comgcd == -1 ? a[i] : gcd(comgcd, a[i])); } int equ = 1; fora(i, 1, n - 1) if(a[i] != a[i + 1]) equ = 0; if(equ == 1){ cout << 0 << endl; continue; } fora(j, 0, 20) //用st表快速计算区间gcd fora(i, 1, n + n + 1 - (1 << j)){ //n + n是将环变为二倍长度的链 if(j == 0) st[i][j] = a[i]; else st[i][j] = gcd(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); } fora(i, 1, n){ int l = i, r = i + n - 1; while(l < r){ //二分查找l使得从i到l的区间gcd == comgcd int mid = (l + r) / 2, k = log2(mid - i + 1); if(gcd(st[i][k], st[mid - (1 << k) + 1][k]) != comgcd) l = mid + 1; //表示从i到mid的区间gcd都还不是最终答案 else r = mid; } ans = max(ans, l - i); } cout << ans << endl; } }
[1547G]. How Many Paths?
变强了再做