《2022牛客寒假算法基础集训营1》
A:假设一个三位数为x1y1z1,有cal(x1y1z1) + cal(x2y2z2) = cal((x1 + x2)(y1 + y2) (z1 + z2))
证明:
我们不进位把每一位看成一个多进制数(实际上和十进制是一样的).
可以得出cal(x1y1z1) = cal(x1 + y1 + z1)。cal(x2y2z2) = cal(x2 + y2 + z2)
cal((x1 + x2)(y1 + y2) (z1 + z2)) = cal(x1 + x2 + y1 + y2 + z1 + z2).
假设当前都到了最下面一层,则有cal(x1 + y1 + z1) + cal(x2 + y2 + z2) = x1 + y1 + z1 + x2 + y2 + z2;
cal(x1 + x2 + y1 + y2 + z1 + z2) = x1 + y1 + z1 + x2 + y2 + z2;
可以出cal(x1y1z1) + cal(x2y2z2) = cal((x1 + x2)(y1 + y2) (z1 + z2)).
那么有了这一步就随便算了。这里dp记了一下。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 1e5 + 5; const int M = 1e7 + 5; const LL Mod = 998244353; #define INF 1e14 #define dbg(ax) cout << "now this num is " << ax << endl; inline long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) { if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } int n,a[N]; LL dp[10],f[10];//和为j的方案数. int cal(int x) { if(x < 10) return x; else { int ff = 0; while(x) { ff += x % 10; x /= 10; } return cal(ff); } } void solve() { scanf("%d",&n); for(int i = 1;i <= n;++i) scanf("%d",&a[i]); for(int i = 1;i <= n;++i) { int now = cal(a[i]); for(int j = 1;j <= 9;++j) f[j] = dp[j]; for(int j = 1;j <= 9;++j) { int tmp = cal(now + j); f[tmp] = ADD(f[tmp],dp[j]); } f[now] = ADD(f[now],1); for(int j = 1;j <= 9;++j) dp[j] = f[j]; } for(int i = 1;i <= 9;++i) printf("%lld%c",dp[i],i == 9 ? '\n' : ' '); } int main() { // int _; // for(scanf("%d",&_);_;_--) { solve(); //} // system("pause"); return 0; }
B:st表预处理一下以取模3(0,1,2)每种开始能增加的值。
然后每次倍增跑区间即可。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 2e5 + 5; const int M = 1e7 + 5; const LL Mod = 998244353; #define INF 1e14 #define dbg(ax) cout << "now this num is " << ax << endl; inline long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) { if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } int n,q,dp[N][20][3];//从i以k开始能得的分 string str; void init() { for(int i = 1;i <= n;++i) { for(int j = 0;j < 3;++j) { if(str[i - 1] == 'D') dp[i][0][j] = 0; else if(str[i - 1] == 'W') dp[i][0][j] = 1; else dp[i][0][j] = (j == 0) ? 0 : -1; } } for(int i = 1;i < 20;++i) { for(int j = 1;j <= n;++j) { int mx = j + (1 << i) - 1; if(mx > n) break; for(int k = 0;k < 3;++k) { int st = k + dp[j][i - 1][k]; dp[j][i][k] = st + dp[j + (1 << (i - 1))][i - 1][st % 3] - k; //printf("dp[%d][%d][%d] is %d\n",j,i,k,dp[j][i][k]); } } } } int query(int L,int r,int s) { int len = (r - L + 1); int k = log2(len); // printf("L is %d r is %d s is %d k is %d\n",L,r,s,k); if((1 << k) == len) return dp[L][k][s]; else { return dp[L][k][s] + query(L + (1 << k),r,(s + dp[L][k][s]) % 3); } } void solve() { scanf("%d %d",&n,&q); cin >> str; init(); while(q--) { int L,r,s;scanf("%d %d %d",&L,&r,&s); printf("%d\n",s + query(L,r,s % 3)); } } int main() { // int _; // for(scanf("%d",&_);_;_--) { solve(); //} // system("pause"); return 0; }
C:尽量往后插。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 2e5 + 5; const int M = 1e7 + 5; const LL Mod = 998244353; #define INF 1e14 #define dbg(ax) cout << "now this num is " << ax << endl; inline long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) { if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } int n,a[105][5],now[105]; int ad[105]; int get(int L,int r) { int sum = ad[L]; for(int i = L + 1;i < r;++i) { sum++; sum += ad[i]; } return sum; } void solve() { scanf("%d",&n); for(int i = 1;i <= n;++i) for(int j = 1;j <= 3;++j) scanf("%d",&a[i][j]); int ans = 0; for(int i = 1;i <= n;++i) { for(int j = 1;j <= 3;++j) { int pos = i - j; if(pos <= 0 || a[i][j] == 0) continue; int len = get(pos,i); if(len < 3) { ad[i - 1] += 3 - len; ans += 3 - len; } // printf("%d %d ans is %d\n",pos,i,ans); } } printf("%d\n",ans); } int main() { // int _; // for(scanf("%d",&_);_;_--) { solve(); //} // system("pause"); return 0; } /* 4 0 0 0 0 0 0 0 1 0 0 1 1 */
D:这题感觉还挺不错的。
很显然最大的是区间里最大的质数。
然后对于前面一部分,就要看欧拉函数了。
因为$\varphi (x) = x \prod_{i = 1}^{k} (1 - \frac{1}{pi})$
可以得知,使质数因子越多就越小。
那么尽量乘小的质因子去计算即可。
这里可能会存在一种情况,就是区间里最小质因子一样多的情况,因为我们一直乘的最小的没乘过的质因子。
所以一定是这些里面x最小的。
大的部分直接暴力找素数就行了(素数之间的间隔最多就几百)
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<double,int> pii; const int N = 1e5 + 5; const int M = 1e7 + 5; #define rep(at,am,as) for(int at = am;at <= as;++at) const LL Mod = 10000; #define INF 1e9 #define dbg(ax) cout << "now this num is " << ax << endl; inline long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) { if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } vector<LL> vec; int prime[45],tot = 0; bool vis[45]; void init() { for(int i = 2;i < 40;++i) { if(!vis[i]) prime[++tot] = i; for(int j = 1;j <= tot && prime[j] * i < 40;++j) { vis[prime[j] * i] = 1; if(i % prime[j] == 0) break; } } LL ma = 1; rep(i,1,tot) { ma *= prime[i]; vec.push_back(ma); } } bool check(int x) { int m = sqrt(x); rep(i,2,m) { if(x % i == 0) return true; } return false; } void solve() { int n;scanf("%d",&n); if(n == 1) printf("-1\n"); else { int pos = upper_bound(vec.begin(),vec.end(),n) - vec.begin(); pos--; while(check(n)) n--; printf("%d %d\n",vec[pos],n); } } int main() { init(); int _; for(scanf("%d",&_);_;_--) { solve(); } //system("pause"); return 0; }
G:
这题感觉还是有点难度的。
我们首先处理出对于每个位置i,在哪个区间里取值可以满足f[i] < min(f[i - 1],f[i + 1])。
然后对于所有的区间我们求一个最小覆盖点的覆盖次数即可。
1:对于第一部分的处理,我们稍微分类考虑一下:假设当前我们是x,另外一端为y
如果x > y,那么显然b必须要小下去才能反转,即界限为:
2b - x < y 即 2b < x + y b < (x + y) / 2.
那么对于x < y,就要2b - x > y 即b > (x + y) / 2;
2:对于第二部分,有很多的做法。
一开始想的是对于区间做的离散化去覆盖然后线段树求一下最小的值。
看到别人有更简便的做法,我们假定区间[L,r],给L赋值为1,r + 1赋值为 - 1,这样离开一个区间就是 + 1 - 1 = 0.
然后求中间的最小值即可。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 1e5 + 5; const int M = 1e7 + 5; #define rep(at,am,as) for(int at = am;at <= as;++at) const LL Mod = 10000; #define INF 1e9 #define dbg(ax) cout << "now this num is " << ax << endl; inline long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) { if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } int a[N]; bool cmp(pii a,pii b) { if(a.first == b.first) return a.second > b.second; else return a.first < b.first; } void solve() { int n;scanf("%d",&n); rep(i,1,n) scanf("%d",&a[i]); vector<pii> vec; int st = 0; rep(i,2,n - 1) { if(a[i] == a[i - 1] || a[i] == a[i + 1]) continue; int L = -INF,r = INF; if(a[i] < a[i - 1]) r = min(r,(a[i] + a[i - 1] - 1) / 2); else L = max(L,(a[i] + a[i - 1]) / 2 + 1); if(a[i] < a[i + 1]) r = min(r,(a[i] + a[i + 1] - 1) / 2); else L = max(L,(a[i] + a[i + 1]) / 2 + 1); if(L <= r) { if(L == -INF) ++st; else vec.push_back(pii{L,1}); if(r < INF) vec.push_back(pii{r + 1,-1}); } } int ans = st; sort(vec.begin(),vec.end(),cmp); for(auto v : vec) { st += v.second; ans = min(ans,st); } printf("%d\n",ans); } int main() { int _; for(scanf("%d",&_);_;_--) { solve(); } // system("pause"); return 0; }
K:钦定前两个是什么,然后dp求最大绿岛数量。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<double,int> pii; const int N = 1e5 + 5; const int M = 1e7 + 5; #define rep(at,am,as) for(int at = am;at <= as;++at) const LL Mod = 10000; #define INF 1e9 #define dbg(ax) cout << "now this num is " << ax << endl; inline long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) { if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } int n; string s; //1 - red,2 - green,3 - black int dp[N][4][4];//i的颜色为k,i - 1颜色为j. int check(int x,int y) { memset(dp,-1,sizeof(dp)); dp[2][x][y] = (x == 2) + (y == 2); int mx = -1; rep(i,1,n) { rep(j,1,3) { rep(k,1,3) { if(dp[i - 1][j][k] == -1) continue; rep(m,1,3) { int sum1 = (j == 2) + (k == 2) + (m == 2),sum2 = (j == 1) + (k == 1) + (m == 1); if(s[i - 1] == 'G') { if(sum1 <= sum2) dp[i][k][m] = max(dp[i][k][m],-1); else dp[i][k][m] = max(dp[i][k][m],dp[i - 1][j][k] + (m == 2)); } if(s[i - 1] == 'R') { if(sum2 <= sum1) dp[i][k][m] = max(dp[i][k][m],-1); else dp[i][k][m] = max(dp[i][k][m],dp[i - 1][j][k] + (m == 2)); } if(s[i - 1] == 'B') { if(sum1 != sum2) dp[i][k][m] = max(dp[i][k][m],-1); else dp[i][k][m] = max(dp[i][k][m],dp[i - 1][j][k] + (m == 2)); } if(i == n) mx = max(mx,dp[i][k][m]); } } } } return mx; } void solve() { cin >> n >> s; int ans = -1; rep(i,1,3) { rep(j,1,3) { ans = max(ans,check(i,j)); } } printf("%d\n",ans); } int main() { // int _; // for(scanf("%d",&_);_;_--) { solve(); //} // system("pause"); return 0; }