题解: 第一题:找规律, 发现儿子减去父亲的编号是Fibonacci数列, 所以就两个儿子一起跳, 就像倍增一样
#include <bits/stdc++.h> using namespace std; #define ll long long ll f[1005]; int main() { // freopen("fibonacci.in", "r", stdin); // freopen("fibonacci.out", "w", stdout); int m; f[1] = 0, f[2] = 1, f[3] = 2; for(int i = 4; i <= 60; i++)f[i] = f[i-1] + f[i-2]; scanf("%d", &m); int lst = 60; while(m--){ ll a, b; scanf("%lld%lld", &a, &b); while(a != b){ if(a < b)swap(a, b); int i; for(i = 60; i >= 0; i--) if(f[i] < a){ break; } a -= f[i]; } printf("%lld ", a); } return 0; }
第二题:我写的分块, 但用map代替的数组, 结果还跑的不如直接for循环,map一次操作log(n), 一定要谨慎用stl;
正解:
#include <bits/stdc++.h> using namespace std; const int M = 3*1e5 + 10; const int N = 570; int a[M]; vector <int> co[M]; void read(int &x){ int f = 1;x= 0;char c= getchar(); while(c<'0'||c>'9'){if(c==-1)f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} x*=f; } int main() { // freopen("color.in","r",stdin); // freopen("color.out","w",stdout); int n, m; scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++){ read(a[i]); co[a[i]].push_back(i); } for(int i = 1; i <= n; i++) sort(co[i].begin(), co[i].end()); while(m--){ int opt, l, r, c; read(opt); if(opt == 1){ read(l), read(r), read(c); int ans = upper_bound(co[c].begin(), co[c].end(), r) - lower_bound(co[c].begin(), co[c].end(), l); printf("%d ", ans); } else { read(l); if(a[l] == a[l+1])continue; (*lower_bound(co[a[l]].begin(), co[a[l]].end(), l))++; (*lower_bound(co[a[l+1]].begin(), co[a[l+1]].end(), l+1))--; swap(a[l], a[l+1]); } } return 0; }
也可以主席树,按下标建,但只有70分;
// luogu-judger-enable-o2 #include <bits/stdc++.h> using namespace std; const int M = 3*1e5 + 10; const int N = 1e6+5; int n, a[M]; struct Node { Node *ls, *rs; int sum; void up(){ sum = ls->sum + rs->sum; } }pool[N*20], *zero, *tail = pool, *root[M]; void init(){ zero = ++tail; root[0] = zero; zero->ls = zero->rs = zero; zero->sum = 0; } Node * newnode(){ Node *nd = ++tail; nd->ls = nd->rs = zero; nd->sum = 0; return nd; } #define Ls nd->ls,l,mid #define Rs nd->rs,mid+1,r int query(int pos, Node *nd, int l = 1, int r = M){ if(nd == zero)return 0; if(l == r)return nd->sum; int mid = (l + r) >> 1; if(pos <= mid && nd->ls)return query(pos, Ls); if(pos > mid && nd->rs)return query(pos, Rs); return 0; } Node * modify(int pos, int val, Node *nd, int l = 1, int r = M){ Node *nnd = newnode(); if(l == r) nnd->sum = nd->sum + val; else { int mid = (l + r) >> 1; int ans = 0; if(pos <= mid){ nnd->ls = modify(pos, val, Ls); nnd->rs = nd->rs; } else { nnd->ls = nd->ls; nnd->rs = modify(pos, val, Rs); } nnd->up(); } return nnd; } int main() { int m; init(); scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++){ scanf("%d", &a[i]); root[i] = modify(a[i], 1, root[i-1]); //printf("LL "); } while(m--){ int opt, l, r, c; scanf("%d", &opt); if(opt == 1){ scanf("%d%d%d", &l, &r, &c); printf("%d ", query(c, root[r]) - query(c, root[l-1])); } else { scanf("%d", &l); root[l] = modify(a[l], -1, root[l]); root[l] = modify(a[l+1], 1, root[l]); swap(a[l], a[l+1]); } } return 0; }
第三题:
对于k==1, 这道题贪心,因为前面要装的少,所以倒着往多装, 对于平方, 枚举看是否有冲突, 也就512^2
对于k == 2, 如果a[j]重复出现,先判定它本身是否影响; 不然看它是否与其他数冲突;
对于一个数它最多可以和集合中两个数冲突, vis[a[j]] 表示他在一个组合中上部分, dvis[a[j]]表示他在一个组合中下部分,
贴的std, 四组不过
#include <bits/stdc++.h> using namespace std; typedef long long LL; #define N 131073 int n, m = 0, K; int a[N], b[N]; bool vis[N], dvis[N], issqr[N * 2]; int f[N * 2]; int getf(int x) {return f[x] > 0 ? (f[x] = getf(f[x])) : x;} void merge(int u, int v) { u = getf(u), v = getf(v); if (u != v) { f[u] += -1; f[v] = u; } } bool check(int u, int v) { int s1 = getf(u), s2 = getf(u + N); int t1 = getf(v), t2 = getf(v + N); if (s1 == t1) return 1; if (s2 == t2) return 1; merge(s1, t2); merge(s2, t1); return 0; } void solve_1() { for (int i = n, j = n; i;) { for (bool flag = 1; j; j--) { for (int k = 1; k * k - a[j] < N; k++) { if (k * k - a[j] <= 0) continue; if (vis[k * k - a[j]]) {flag = 0; break;} } if (!flag) break; vis[a[j]] = 1; } if (!j) break; b[++m] = j; for ( ; i > j; i--) vis[a[i]] = 0; } } void solve_2() { memset(f, -1, sizeof f); for (int i = 1; i * i < 2 * N; i++) issqr[i * i] = 1; for (int i = n, j = n; i;) { for (bool flag = 1; j; j--) { if (vis[a[j]]) { if (issqr[a[j] + a[j]]) { if (dvis[a[j]]) break; for (int k = 1; k * k - a[j] < N; k++) { if (k * k - a[j] <= 0) continue; if (vis[k * k - a[j]] && k * k != a[j] * 2) { flag = 0; break; } } if (!flag) break; dvis[a[j]] = 1; } } else { for (int k = 1; k * k - a[j] < N; k++) { if (k * k - a[j] <= 0) continue; if (vis[k * k - a[j]]) { if (check(k * k - a[j], a[j])) {flag = 0; break;} } } if (!flag) break; vis[a[j]] = 1; } } if (!j) break; b[++m] = j; for ( ; i > j; i--) f[a[i]] = f[a[i] + N] = -1, vis[a[i]] = 0, dvis[a[i]] = 0; } } int main() { ///freopen("division.in", "r", stdin); //freopen("division.out", "w", stdout); scanf("%d%d", &n, &K); for (int i = 1; i <= n; i++) scanf("%d", a + i); if (K == 1) solve_1(); else solve_2(); printf("%d ", m + 1); for (int i = m; i; i--) printf("%d ", b[i]); putchar(' '); return 0; }
•第一题考察:观察性质,求斐波那契数列。
•相似题目:(嗨呀我还真没找到类似的 NOIp 题目)
•第二题考察:排序,二分查找。(或者可以使用高级数据结构)
•相似题目:「NOIp 2012」借教室
•第三题考察:观察性质,并查集,复杂度分析。
•相似题目:「NOIp 2010」关押罪犯