牛客小白月赛20
有一说一最近状态确实不太行,打了这么久还是停留在初等小白。
A.斐波那契
求斐波那契数列前n项的平方和。这是斐波那契数列面积的应用,就是求f[n] * f[n + 1],用俩次矩阵快速幂求得。o(logn)
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const int N = 2; 8 const ll mod = 1e9 + 7; 9 10 ll n; 11 12 ll temp[N][N], res[N][N]; 13 14 void muti(ll a[][N], ll b[][N], int n) 15 { 16 memset(temp, 0, sizeof(temp)); 17 for (ll i = 0; i < n; i ++) 18 { 19 for (ll j = 0; j < n; j ++) 20 { 21 for (ll k = 0; k < n; k ++) 22 { 23 temp[i][j] += (a[i][k] * b[k][j]) % mod; 24 } 25 temp[i][j] %= mod; 26 } 27 } 28 for (ll i = 0; i < n; i ++) 29 for(ll j = 0; j < n; j ++) 30 a[i][j] = temp[i][j]; 31 } 32 33 void Pow(ll a[][N], ll m, int n) 34 { 35 memset(res, 0, sizeof(res)); 36 for (ll i = 0; i < n; i ++) res[i][i] = 1; 37 while(m) 38 { 39 if(m& 1) muti(res, a, n); 40 muti(a, a, n); 41 m >>= 1; 42 } 43 } 44 45 int main() 46 { 47 scanf("%lld", &n); 48 ll a[N][N]; 49 a[0][0] = 1, a[0][1] = 1, a[1][0] = 1, a[1][1] = 0; 50 Pow(a, n, 2); 51 ll ans1 = res[1][0]; 52 a[0][0] = 1, a[0][1] = 1, a[1][0] = 1, a[1][1] = 0; 53 Pow(a, n + 1, 2); 54 ll ans2 = res[1][0]; 55 printf("%lld\n", ((ans1 % mod ) * (ans2 % mod)) % mod); 56 }
B.最大边长
打的时候不知道为什么被这样的题卡了很久。假设x < y,那么在x 上只能存在一个正方形,y存在3个, 或者x存在两个, y存在两个。反之也成立。
1 //#include<bits/stdc++.h> 2 #pragma GCC optimize(2) 3 #pragma G++ optimize(2) 4 #include<map> 5 #include<set> 6 #include<cmath> 7 #include<ctime> 8 #include<queue> 9 #include<stack> 10 #include<cstdio> 11 #include<random> 12 #include<string> 13 #include<vector> 14 #include<cstring> 15 #include<utility> 16 #include<iostream> 17 #include<algorithm> 18 #include<functional> 19 #include<unordered_map> 20 #include<unordered_set> 21 using namespace std; 22 23 #define ios ios::sync_with_stdio(false) 24 #define ll long long 25 #define pa pair<int,int> 26 #define mk make_pair 27 #define sc(n) scanf("%d",&n) 28 #define ss(s) scanf("%s",s) 29 #define fo(i, a, b) for(int i = a; i <= b; i++) 30 #define of(i, a, b) for(int i = a; i >= b; i--) 31 #define mem(a, b) memset(a, b, sizeof a) 32 #define copy(a,b) memcpy(a, b, sizeof b) 33 #define pi acos(-1) 34 #define input freopen("input.in", "r", stdin); 35 #define output freopen("output.out", "w", stdout); 36 37 const ll inf = 0x3f3f3f3f; 38 const ll mod = 1e9 + 7; 39 const ll N = 2e5 + 10; 40 const ll M = 1e4 + 10; 41 const double eps = 1e-10; 42 43 using namespace std; 44 45 int t, n; 46 47 int main() 48 { 49 ll a, b, c; 50 cin >> a >> b; 51 ll ans = 0; 52 if (a / 3 >= b) 53 ans = max(ans, b); 54 if (b / 3 >= a) 55 ans = max(ans, a); 56 if (b / 2 * 2 <= a) 57 ans = max(ans, b / 2); 58 if (a / 2 * 2 <= b) 59 ans = max(ans, a / 2); 60 cout << ans << endl; 61 return 0; 62 }
C.球的表面积
做这题必须知道球冠的表面积公式2πRH, R为球半径,H为球冠的高。若两个球相离,则是面积相加。若包含关系,则输出较大的面积。若相加,就是俩个球冠的表面积被除去。
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<iostream> 5 #include<string> 6 #include<vector> 7 #include<math.h> 8 using namespace std; 9 #define ll long long 10 #define PI 3.1415926 11 int main() 12 { 13 double x1,y1,z1,r1,x2,y2,z2,r2; 14 scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&x1,&y1,&z1,&r1,&x2,&y2,&z2,&r2); 15 double ans1=4*PI*r1*r1; 16 double ans2=4*PI*r2*r2; 17 double len=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2)); 18 if(len>=r1+r2) 19 { 20 printf("%.6lf\n",ans1+ans2); 21 } 22 else if((len<r1+r2)&&(len>max(r1,r2)-min(r1,r2))) 23 { 24 double cosa=(r1*r1+len*len-r2*r2)/(2*r1*len*1.00000); 25 double dis1=cosa*r1; 26 double h1=r1-dis1; 27 double s1=ans1-2*PI*r1*h1; 28 29 double cosb=(r2*r2+len*len-r1*r1)/(2*r2*len*1.00000); 30 double dis2=cosb*r2; 31 double h2=r2-dis2; 32 double s2=ans2-2*PI*r2*h2; 33 printf("%.6lf\n",s1+s2); 34 } 35 else if(len<=max(r1,r2)-min(r1,r2)) 36 { 37 printf("%lf\n",max(ans1,ans2)); 38 } 39 }
D.3的倍数
发现n很小,直接暴力。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 int n; 6 char s[20][10010]; 7 8 int f[20][36]; 9 int res[36]; 10 int ans; 11 12 bool check() 13 { 14 for (int i = 1; i <= 26; i ++) 15 { 16 if(res[i] % 3) return false; 17 } 18 return true; 19 } 20 21 void dfs(int u, int cnt) 22 { 23 if(u == n + 1) 24 { 25 if(check()) 26 ans = max(ans, cnt); 27 return ; 28 } 29 for (int j = 1; j <= 26; j ++) res[j] += f[u][j]; 30 dfs(u + 1, cnt + 1); 31 for (int j = 1; j <= 26; j ++) res[j] -= f[u][j]; 32 dfs(u + 1, cnt); 33 } 34 35 int main() 36 { 37 scanf("%d", &n); 38 for (int i = 1; i <= n; i ++) 39 { 40 scanf("%s", s[i] + 1); 41 int len = strlen(s[i] + 1); 42 for (int j = 1; j <= len; j ++) 43 { 44 f[i][s[i][j] - 'A' + 1] ++; 45 } 46 } 47 dfs(1, 0); 48 cout << ans << endl; 49 }
E.区区区间
这题明示线段是,但是本人因为最近学了分块,结果一直想要分块,结果自闭住。其实线段树比较好想,用lazy数组去维护区间最左端的值。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const int N = 2e5 + 10; 8 9 int n, m; 10 ll a[N]; 11 ll sum[N << 2], lazy[N << 2]; 12 13 void pushup(int rt) 14 { 15 sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; 16 } 17 18 void pushdown(int rt, int llen, int rlen) 19 { 20 if(lazy[rt]) 21 { 22 lazy[rt << 1] = lazy[rt]; 23 lazy[rt << 1 | 1] = lazy[rt] + llen; 24 sum[rt << 1] = 1ll * (lazy[rt] + lazy[rt] + llen - 1) * llen / 2; 25 sum[rt << 1 | 1] = 1ll * (lazy[rt << 1 | 1] + lazy[rt << 1 | 1] + rlen - 1) * rlen / 2; 26 lazy[rt] = 0; 27 } 28 } 29 30 void build(int l, int r, int rt) 31 { 32 if(l == r) 33 { 34 sum[rt] = a[l]; 35 lazy[rt] = 0; 36 return ; 37 } 38 int mid = l + r >> 1; 39 build(l, mid, rt << 1), build(mid + 1, r, rt << 1 | 1); 40 pushup(rt); 41 } 42 43 ll query(int L, int R, int l, int r, int rt) 44 { 45 ll ans = 0; 46 if(L <= l && R >= r) 47 { 48 return sum[rt]; 49 } 50 int mid = l + r >> 1; 51 pushdown(rt, mid - l + 1, r - mid); 52 if(L <= mid) ans += query(L, R, l, mid, rt << 1); 53 if(R > mid) ans += query(L, R, mid + 1, r, rt << 1 | 1); 54 return ans; 55 } 56 57 void update(int L, int R, int C,int l, int r, int rt) 58 { 59 if(L <= l && R >= r) 60 { 61 sum[rt] = 1ll * (r - l + 1) * (C - L + l + C - L + l + r - l) / 2; 62 lazy[rt] = C - L + l; 63 return ; 64 } 65 int mid = l + r >> 1; 66 pushdown(rt, mid - l + 1, r - mid); 67 if(L <= mid) update(L, R, C, l, mid, rt << 1); 68 if(R > mid) update(L, R, C, mid + 1, r, rt << 1 | 1); 69 pushup(rt); 70 } 71 72 int main() 73 { 74 scanf("%d%d", &n, &m); 75 for (int i = 1; i <= n; i ++) 76 scanf("%lld", &a[i]); 77 build(1, n, 1); 78 while(m --) 79 { 80 int op; 81 scanf("%d", &op); 82 if(op == 1) 83 { 84 int l, r, k; 85 scanf("%d%d%d", &l, &r, &k); 86 update(l, r, k, 1, n, 1); 87 } 88 else 89 { 90 int l, r; 91 scanf("%d%d", &l, &r); 92 printf("%lld\n", query(l, r, 1, n, 1)); 93 } 94 } 95 }
F.进制转换
用短除法。基本操作。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 int n, m, k; 6 7 char s[2200]; 8 9 vector<int>a; 10 11 int main() 12 { 13 scanf("%s", s + 1); 14 scanf("%d%d", &m, &k); 15 int len = strlen(s + 1); 16 for (int i = len; i >= 1; i --) 17 { 18 if(s[i] >= '0' && s[i] <= '9') 19 { 20 a.push_back(s[i] - '0'); 21 } 22 else if(s[i] >= 'a' && s[i] <= 'z') 23 { 24 a.push_back(s[i] - 'a' + 10); 25 } 26 } 27 vector<int> res; 28 while(a.size()) 29 { 30 int t = 0; 31 for (int i = a.size() - 1; i >= 0; i --) 32 { 33 a[i] += t * m; 34 t = a[i] % k; 35 a[i] /= k; 36 } 37 res.push_back(t); 38 while(a.size() && !a.back()) a.pop_back(); 39 } 40 reverse(res.begin(), res.end()); 41 string b_line; 42 for (auto x : res ) 43 { 44 if (x <= 9) b_line += char('0' + x); 45 else b_line += char('a' + x - 10); 46 } 47 cout << b_line << endl; 48 }
G.快乐风男
求最长严格上升子序列字典序最小的。那么直接贪心,先二分求出每个a[i]应该出现在上升数组的哪个位置。然后对位置进行贪心。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int N = 1e5 + 10; 6 const int INF = 0x3f3f3f3f; 7 8 int n; 9 int a[N], cnt, f[N]; 10 11 int len[N], first[N]; 12 int ans[N]; 13 14 int main() 15 { 16 memset(f, 0x3f, sizeof(f)); 17 scanf("%d", &n); 18 for (int i = 1; i <= n; i ++) 19 scanf("%d", &a[i]); 20 for (int i = 1; i <= n; i ++) 21 { 22 int t = lower_bound(f + 1, f + n + 1, a[i]) - f; 23 if(f[t] == INF) 24 { 25 ++ cnt; 26 f[t] = a[i]; 27 len[i] = t; 28 } 29 else 30 { 31 f[t] = a[i]; 32 len[i] = t; 33 } 34 if(first[len[i]] == 0) first[len[i]] = i; 35 } 36 printf("%d\n", cnt); 37 ans[cnt] = first[cnt]; 38 for (int i = first[cnt] - 1; i >= 1; i --) 39 { 40 if(a[i] < a[ans[len[i] + 1]]) 41 ans[len[i]] = i; 42 } 43 for(int i = 1; i <= cnt; i++) 44 printf("%d%c", ans[i], i==cnt?'\n':' '); 45 }
H.好点
类似二位偏序,只要求右上角不存在的情况,那么按横坐标从小到大,从后往前开始记录,若它的纵坐标最大,其右上角一定不存在点。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 5e5 + 100; 5 const int mod = 1e9 + 7; 6 int n, m; 7 struct node{ 8 int x, y; 9 bool operator<(const node &a)const{ 10 return x < a.x; 11 } 12 }a[maxn],ans[maxn]; 13 int main(){ 14 cin >> n; 15 for (int i = 1; i <= n; i++) 16 scanf("%d%d", &a[i].x, &a[i].y); 17 sort(a + 1, a + 1 + n); 18 int my = -1e9-1; 19 int num = 0; 20 for (int i = n; i>= 1; i--){ 21 if (a[i].y > my){ 22 my = a[i].y; 23 ans[++num].x = a[i].x; 24 ans[num].y = a[i].y; 25 } 26 } 27 sort(ans + 1, ans + 1 + num); 28 for (int i = 1; i <= num; i++) 29 cout << ans[i].x << " " << ans[i].y << endl; 30 return 0; 31 }
I.小小小马
对于n <= 3 && m <= 3(除了n == 1 && m == 1)都不可行,其余都可行。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 typedef pair<int, int> PII; 6 7 const int N = 2e3 + 10; 8 9 int n, m; 10 11 bool st[N][N]; 12 13 14 int main() 15 { 16 scanf("%d%d", &n, &m); 17 if(n == 1 && m == 1) 18 { 19 puts("Yes"); 20 return 0; 21 } 22 if(n == 1 || m == 1) 23 { 24 puts("No"); 25 return 0; 26 } 27 if(n == 2 || m == 2) 28 { 29 puts("No"); 30 return 0; 31 } 32 if(n <= 3 && m <= 3) 33 { 34 puts("No"); 35 return 0; 36 } 37 puts("Yes"); 38 39 }
J.dh的帽子
典型的数位DP,一个上界一个下界。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 ll dp[32][2][2][2][2][2][2]; 8 int num1[32], num2[32]; 9 10 11 ll dfs(int len, bool lim1, bool lim2, bool lim3, bool im1, bool im2, bool im3) 12 { 13 if(len == -1) return 1; 14 if(dp[len][lim1][lim2][lim3][im1][im2][im3] != -1) return dp[len][lim1][lim2][lim3][im1][im2][im3]; 15 ll ans = 0; 16 int up1 = lim1 ? num2[len] : 1; 17 int up2 = lim2 ? num2[len] : 1; 18 int up3 = lim3 ? num2[len] : 1; 19 int down1 = im1 ? num1[len] : 0; 20 int down2 = im2 ? num1[len] : 0; 21 int down3 = im3 ? num1[len] : 0; 22 for (int i = 0; i <= up1; i ++) 23 for (int j = 0; j <= up2; j ++) 24 for (int k = 0; k <= up3; k ++) 25 { 26 if(i < down1 || j < down2 || k < down3) continue; 27 if((i ^ j ^ k) != (i | j | k)) continue; 28 ans += dfs(len - 1, lim1 && i == up1, lim2 && j == up2, lim3 && k == up3, im1 && i== down1, im2 && j == down2, im3 && k == down3); 29 } 30 return dp[len][lim1][lim2][lim3][im1][im2][im3] = ans; 31 } 32 33 //ll dfs(int len, bool limit1, bool limit2, bool limit3, bool ismin1, bool ismin2, bool ismin3) 34 //{ 35 // if (len == -1) 36 // return 1; 37 // 38 // if (dp[len][limit1][limit2][limit3][ismin1][ismin2][ismin3] != -1) 39 // return dp[len][limit1][limit2][limit3][ismin1][ismin2][ismin3]; 40 // 41 // int up1 = limit1 ? num2[len] : 1; 42 // int up2 = limit2 ? num2[len] : 1; 43 // int up3 = limit3 ? num2[len] : 1; 44 // int un1 = ismin1 ? num1[len] : 0; 45 // int un2 = ismin2 ? num1[len] : 0; 46 // int un3 = ismin3 ? num1[len] : 0; 47 // ll ans = 0; 48 // for (int i = 0; i <= up1; i++) 49 // { 50 // for (int j = 0; j <= up2; j++) 51 // { 52 // for (int l = 0; l <= up3; l++) 53 // { 54 // if (i < un1 || j < un2 || l < un3) 55 // continue; 56 // if ((i ^ j ^ l) != (i | j | l)) 57 // continue; 58 // ans += dfs(len - 1, limit1 && i == up1, limit2 && j == up2, limit3 && l == up3, ismin1 && i == un1, ismin2 && j == un2, ismin3 && l == un3); 59 // } 60 // } 61 // } 62 // return dp[len][limit1][limit2][limit3][ismin1][ismin2][ismin3] = ans; 63 //} 64 65 66 ll solve(int l, int r) 67 { 68 for (int i = 0; i <= 30; i ++) 69 { 70 num1[i] = (l >> i) & 1; 71 num2[i] = (r >> i) & 1; 72 // cout << num1[i] << " " << num2[i] << endl; 73 } 74 return dfs(30, true, true, true, true, true, true); 75 } 76 77 int main() 78 { 79 int l, r; 80 memset(dp, -1, sizeof(dp)); 81 scanf("%d%d", &l, &r); 82 printf("%lld\n", solve(l, r)); 83 }
K.Hellow World
就真Hellow Horld。