《2021牛客寒假算法基础集训营2》
H:签到。
F:可以发现长度就是1,2,3这些第一个不在自己i位置上的,他们自己的位置减去i。
长度找到后就去翻转验证能不能行即可。
本来应该是要双端队列去模拟这个过程的,暴力翻转复杂度肯定不够。
但是懒得写队列暴力了写了下过了。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 1e5 + 5; const int M = 5e6 + 5; const LL Mod = 1e9 + 7; #define pi acos(-1) #define INF 1e9 #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } } using namespace FASTIO; int a[N],pos[N],pre[N],nxt[N],rev[N];//rev = 1前换到后,rev2 = 后换到前 int main() { int n;n = read(); for(int i = 1;i <= n;++i) a[i] = read(),pos[a[i]] = i; int f = 0; for(int i = 1;i <= n;++i) if(a[i] != i) f = 1; if(f == 0) printf("yes\n1\n"); else{ int tag = 0,len,ok = 1; for(int i = 1;i <= n;++i){ if(tag == 0){ if(a[i] == i) continue; tag = 1; len = pos[i] - i + 1; for(int j = 1;j <= len / 2;++j) { swap(a[i + j - 1],a[i + len - j]); } } else{ if(a[i] == i) continue; else{ int to = i + len - 1; if(a[to] != i) { ok = 0; break; } else{ for(int j = 1;j <= len / 2;++j){ swap(a[i + j - 1],a[i + len - j]); } } } } // printf("ronud %d\n",i); // for(int i = 1;i <= n;++i) printf("%d%c",a[i],i == n ? '\n' : ' '); } if(ok == 1){ printf("yes\n"); printf("%d\n",len); } else printf("no\n"); } //system("pause"); return 0; }
I:线性筛。
因为直接存会爆longlong,中间取模的话又会导致答案不对。
所以我用了字符串来拼接,最后算值,string稍微有点慢,卡了卡常数才过了。
其实每个值只会爆一次筛选到,所以可以连父节点边,然后树上就可以dp统计贡献即可。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 4e6 + 5; const int M = 5e6 + 5; const LL Mod = 1e9 + 7; #define pi acos(-1) #define INF 1e9 #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } } using namespace FASTIO; string f[N]; LL prime[N],tot = 0,ans = 0; bool vis[N]; LL cal(string s){ LL ans = 0; int len = s.size(); for(int i = 0;i < len;++i){ ans = (ans * 10 % Mod + (s[i] - '0')) % Mod; } return ans; } void init(int NN){ for(int i = 2;i <= NN;++i){ if(!vis[i]){ f[i] = to_string(i); prime[++tot] = i; ans = (ans + i) % Mod; } for(int j = 1;j <= tot && prime[j] * i <= NN;++j){ vis[i * prime[j]] = 1; f[i * prime[j]] = to_string(prime[j]) + f[i]; ans = (ans + cal(f[i * prime[j]])) % Mod; if(i % prime[j] == 0) break; } } } int main() { int n;n = read(); init(n); printf("%lld\n",ans); //system("pause"); return 0; }
J:这题其实不难,但是比赛中想错了。
首先,前面几个用f[i] = f[i - 1] + f[i - 2]来即可。
我们想要复杂度尽可能高,就需要让第一重循环i尽可能多,一开始就是这里没想清楚。
其实后面全插入1的话并且从2开始,这样就满足1 + 1 < f[i],无法构成三角形。这样可以前面的f[i]都无法满足。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 1e5 + 5; const int M = 5e6 + 5; const LL Mod = 1e9 + 7; #define pi acos(-1) #define INF 1e9 #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } } using namespace FASTIO; LL f[N]; int main() { int n;n = read(); f[0] = 1,f[1] = 2; int up = 40; for(int i = 2;i <= n;++i){ if(i <= up) f[i] = f[i - 1] + f[i - 2 ]; else f[i] = 1; } for(int i = 1;i <= n;++i) printf("%d%c",f[i],i == n ? '\n' : ' '); //system("pause"); return 0; }
D:这题都往整除分块方向想了。
其实就是个找规律。
打表排序后可以发现,以$[\sqrt{n]}$为分界,一边就是1 ~ 这个值。一边就是n / 左边的值可以得到。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 1e5 + 5; const int M = 5e6 + 5; const LL Mod = 1e9 + 7; #define pi acos(-1) #define INF 1e9 #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } } using namespace FASTIO; int main() { int ca;ca = read(); while(ca--) { int n,x;n = read(),x = read(); int m = sqrt(n),sz; if(n / m == m) sz = 2 * m - 1; else sz = 2 * m; int ma = n / x; if(ma <= m) printf("%d\n",sz - ma + 1); else printf("%d\n",n / ma); } //system("pause"); return 0; }
E:一开始扫了一眼以为是贪心直接跳了。
其实是bfs,这题难在建图。
观察到y的范围很小,所以按y存,之后每个vector里按左边界升序,这样同高度的连边就很简单。
然后对于不同高度的就用双指针去维护,因为没有交叉的面积,所以双指针可以保证每个点基本只扫一遍,这样建图复杂度在O(n)。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 1e5 + 5; const int M = 5e6 + 5; const LL Mod = 1e9 + 7; #define pi acos(-1) #define INF 1e9 #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } } using namespace FASTIO; struct Node{ int L,r,id; bool operator < (const Node a)const{ return L < a.L; } }; vector<Node> vec[N]; vector<int> G[N]; int ans[N],n; bool vis[N]; int bfs(){ queue<int> Q; Q.push(1); ans[1] = 0; vis[1] = 1; while(!Q.empty()){ int u = Q.front(); Q.pop(); if(u == n) return ans[u]; for(auto v : G[u]){ if(!vis[v]){ vis[v] = 1; ans[v] = ans[u] + 1; Q.push(v); } } } } int main() { n = read(); for(int i = 1;i <= n;++i){ int y,L,r;y = read(),L = read(),r = read(); vec[y].push_back(Node{L,r,i}); } for(int i = 0;i < N;++i) sort(vec[i].begin(),vec[i].end()); for(int i = 0;i < N;++i){ if(vec[i].size() == 0) continue; int st = 0; for(int j = 0;j < vec[i].size();++j){ if(j < vec[i].size() - 1 && vec[i][j + 1].L == vec[i][j].r){//同y相邻连边 int u = vec[i][j].id,v = vec[i][j + 1].id; G[u].push_back(v); G[v].push_back(u); } while(st < vec[i + 1].size() && vec[i + 1][st].r <= vec[i][j].L) st++;//先满足左边在里面 while(st < vec[i + 1].size() && vec[i + 1][st].L < vec[i][j].r) { int u = vec[i][j].id,v = vec[i + 1][st].id; G[u].push_back(v); G[v].push_back(u); st++; } if(st != 0) st--;//上一层可能这个块横跨了多个块 } } printf("%d\n",bfs()); system("pause"); return 0; }
C:分类找规律构造。一开始以为后缀树之类的就没看。
G:离散化模拟,其实并不需要扫描线。看码力。
A:待补
B:待补。