CSP-S模拟1
背景图太花哨了,所以我把它去掉了。
A. 斐波那契
我本来以为算到56就够了,数0数错了就很***,fibo要算到70
一开始还以为编号越大深度越小,然后发现题面上给的图都不满足……(交上去是90分,数据够水的)
就开始找深度,每跳一层查一遍深度TLE70,后来发现往上跳深度直接减1就行了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = -2; const int N = 60; const ll mod = 1e9 + 7; ll fibo[70], f2[70], m; inline ll read() { ll x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } inline ll getfa(ll x) { ll y = upper_bound(f2+1, f2+N+1, x)-f2-1; return x - f2[y] + 1; } void init() { fibo[1] = 1; fibo[2] = 1; fibo[3] = 1; for(int i=4; i<=N; i++) { fibo[i] = fibo[i-1] + fibo[i-2]; } f2[1] = 1; for(int i=2; i<=N; i++) { f2[i] = f2[i-1] + fibo[i-1]; if(f2[i] < 0) break; } } inline ll getdep(ll x) { int ret = 0; while(x != 1) { x = getfa(x); ret++; } return ret; } int main() { init(); m = read(); while(m--) { ll a = read(), b = read(); ll depa = getdep(a), depb = getdep(b); while(a != b) { if(depa < depb) { swap(a, b); swap(depa, depb); } a = getfa(a); depa--; } printf("%lld\n", a); } return 0; }
B. 数颜色
暴力就可以有40分,写了个分块还写错了WA10,算了一个可持久化权值线段树的空间还以为不够用……
%%%wenqizhi1125 指出蓝书上分块的蒲公英那个题(求区间众数)的查找位置和这个题很相似。
本来对于lower_bound的返回值犹豫了半天,然后发现我想到的都是些蠢问题,比如lower_bound找的是大于等于的第一个,我以为查找一个比最小的数还小的东西会返回-1。
vector的sort也是这个格式。
关于相对位置为什么不会改变这个问题——交换的是相邻的两个啊,而且还颜色不一样。颜色一样当然可以直接换。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = -2; const int N = 3e5 + 6; const ll mod = 1e9 + 7; int n, m, ans, a[N]; vector<int> vec[N]; inline int read() { ll x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { n = read(); m = read(); for(int i=1; i<=n; i++) { a[i] = read(); vec[a[i]].push_back(i); } while(m--) { int tp = read(); if(tp == 1) { int l = read(), r = read(), c = read(); int k1 = lower_bound(vec[c].begin(), vec[c].end(), l)-vec[c].begin(); int k2 = upper_bound(vec[c].begin(), vec[c].end(), r)-vec[c].begin()-1; ans = k2 - k1 + 1; printf("%d\n", ans); } else { int x = read(), c1 = a[x], c2 = a[x+1]; int k = lower_bound(vec[c1].begin(), vec[c1].end(), x)-vec[c1].begin(); vec[c1][k] = x + 1; k = lower_bound(vec[c2].begin(), vec[c2].end(), x+1)-vec[c2].begin(); vec[c2][k] = x; swap(a[x], a[x+1]); } } return 0; }
C. 分组
针对数据搞了一个部分分64:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 131099; const int N = 5e4 + 3; const ll mod = 1e9 + 7; int n, k, a[maxn], pos[maxn], cnt; bool f = 1; inline int read() { ll x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { n = read(); k = read(); for(int i=1; i<=n; i++) { a[i] = read(); if(a[i] > 2) f = 0; } if(f) { for(int i=1; i<=n; i++) { if(a[i] == 2) pos[++cnt] = i; } cnt--; if(k == 1) { printf("%d\n", cnt+1); for(int i=1; i<=cnt; i++) { printf("%d ", pos[i]); } printf("\n"); } else { if(cnt & 1) { printf("%d\n", cnt/2+1); for(int i=2; i<=cnt; i+=2) { printf("%d ", pos[i]); } printf("\n"); } else { printf("%d\n", cnt/2+1); for(int i=1; i<=cnt; i+=2) { printf("%d ", pos[i]); } printf("\n"); } } exit(0); } //k = 1 int r = n; for(int i=n; i>=1; i--) { for(int j=r; j>i; j--) { if(a[i] + a[j] == (int)pow((int)sqrt(a[i]+a[j]), 2)) { r = i; pos[++cnt] = i; break; } } } if(k == 1) { printf("%d\n", cnt+1); for(int i=cnt; i>=1; i--) { printf("%d ", pos[i]); } printf("\n"); } else { printf("%d\n", cnt/2+1); if(cnt & 1) { for(int i=cnt-1; i>=1; i-=2) { printf("%d ", pos[i]); } printf("\n"); } else { for(int i=cnt; i>=1; i-=2) { printf("%d ", pos[i]); } printf("\n"); } } return 0; }
优化查找比较神奇,可以去枚举这个平方数,看看差值是不是在当前组出现过。
vector<int>().swap(fairy[a[q]]) 其实就是清空的意思。
Copy from %%%Varuxn
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 131099; const int N = 5e4 + 3; const ll mod = 1e9 + 7; int n, k, a[maxn], pos[maxn], cnt, fa[maxn<<1]; vector<int> fairy[maxn<<1]; bool v[maxn<<1];//不开二倍会WA inline int read() { ll x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int find(int x) { if(x == fa[x]) return x; return fa[x] = find(fa[x]); } int main() { n = read(); k = read(); int r = n; for(int i=1; i<=n; i++) { a[i] = read(); } if(k == 1) { for(int i=n; i>=1; i--) { bool flag = 1; //尽管找的是另一个单值,但是循环枚举到了和,不开二倍会导致数组越界! for(int j=1; j<=512; j++) { if(j*j >= a[i]) { if(v[j*j-a[i]]) { flag = 0; break; } } } if(!flag) { for(int j=i+1; j<=r; j++) { v[a[j]] = 0; } pos[++cnt] = i; r = i; } v[a[i]] = 1; } printf("%d\n", cnt+1); for(int i=cnt; i>=1; i--) { printf("%d ", pos[i]); } } else { for(int i=1; i<=(n<<1); i++) { fa[i] = i; } for(int i=n; i>=1; i--) { for(int j=1; j<=512; j++) { if(j*j >= a[i]) { if(fairy[j*j-a[i]].size()) { for(int p=0; p<fairy[j*j-a[i]].size(); p++) { int now = fairy[j*j-a[i]][p]; if(find(now) == find(i)) { for(int q=i+1; q<=r; q++) { vector<int>().swap(fairy[a[q]]); } pos[++cnt] = i; r = i; } else { fa[find(i+n)] = find(now); fa[find(now+n)] = find(i); } } } } } fairy[a[i]].push_back(i); } printf("%d\n", cnt+1); for(int i=cnt; i>=1; i--) { printf("%d ", pos[i]); } } return 0; }
时光花火,水月星辰