Codeforces Round #153 (Div. 2)
A.
暴力, 水题
B.
n <= 2 都输出-1, 其它必然存在一对满足题意的数, 而且 这对数相邻, 注意到这点的话,就容易做多了,直接暴力找解

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[100005], b[100005]; int main() { int i, j, n; scanf("%d", &n); for(i = 0; i < n ;i++) scanf("%d", &a[i]), b[i] = a[i]; if(n <= 2) { puts("-1"); return 0;} sort(b, b+n); for(i = 0; i < n-1; i++) { if(a[i] == a[i+1]) continue; swap(a[i], a[i+1]); for(j = 0; j < n && a[j] == b[j]; j++); //如果换了是顺序或逆序再换回来 if(j == n) { swap(a[i], a[i+1]); continue; } for(j = 0; j < n && a[j] == b[n-j-1]; j++); if(j == n) { swap(a[i], a[i+1]); continue; } printf("%d %d\n", i+1, i+2); return 0; } puts("-1"); }
C.
单调队列( two points)

#include<cstdio> #include<cstring> #include<queue> using namespace std; #define LL __int64 int a, n, d; LL ans; queue <int> q; int main() { int i, j; scanf("%d%d", &n, &d); for(i = 0; i < n; i++) { scanf("%d", &a); q.push(a); while(q.front() < q.back() - d) q.pop(); j = q.size()-1; ans += (LL)j * (j-1)/2; } printf("%I64d\n", ans); }
二分

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define LL __int64 int d, n; int a[100005]; LL ans; int main() { int i, j; scanf("%d%d", &n, &d); for(i = 0; i < n; i++) scanf("%d", &a[i]); for(i = 1; i < n; i++) j = i - (lower_bound(a, a+i, a[i] - d) - a), ans += (LL)j *(j-1)/2; printf("%I64d\n", ans); return 0; }
D.
注意两个操作的关系,做一次操作1和一次操作2就会回到原来的序列, 分别求出只做操作1和只做操作2就能回到原来序列的周期a,b
根据a,b和给定的k能得出结论

#include<cstdio> #include<cstring> int q[103], p[103], s[103], pp[103]; int n, k, a, b; int main() { int i, j; scanf("%d%d", &n, &k); for(i = 1; i <= n; i++) scanf("%d", &q[i]); for(i = 1; i <= n; i++) scanf("%d", &s[i]); //求解操作1的周期 for(i = 1; i <= n; i++) pp[i] = p[i] = i; while(a <= k) { for(j = 1; j <= n && p[j] == s[j]; j++); if(j == n+1) break; for(j = 1; j <= n; j++) pp[j] = p[q[j]]; for(j = 1; j <= n; j++) p[j] = pp[j]; a++; } //求解操作2的周期 for(i = 1; i <= n; i++) pp[i] = p[i] = i; while(b <= k) { for(j = 1; j <= n && p[j] == s[j]; j++); if(j == n+1) break; for(j = 1; j <= n; j++) pp[q[j]] = p[j]; for(j = 1; j <= n; j++) p[j] = pp[j]; b++; } //对两边周期都为1进行特判 if(a == 1 && b == 1 && k == 1) puts("YES"); else if(a == 1 && b == 1) puts("NO"); else if(a == k+1 && b == k+1) puts("NO"); // 两边都走不到 else if(!a && !b) puts("NO"); //一开始的串就是目标(a == 0 && b == 0) else if(((b+k+1)&1) || ((a+k+1)&1)) puts("YES"); //左右只要有一边可以到达 else puts("NO"); return 0; }
E.
周期为t = 360360(2到15的最小公倍数), 想了很久就是不知道为什么,求大神证明。

#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define LL __int64 const LL t = 360360; LL a, b, k; LL min(LL a, LL b) { return a < b ? a : b; } LL gao(LL a, LL b) { LL c = 0; while(a != b) { LL tp = a-1; for(int i = 2; i <= k; i++) if(a/i*i >= b) tp = min(tp, a/i*i); c++; a = tp; } return c; } int main() { scanf("%I64d%I64d%I64d", &a, &b, &k); if(a/t == b/t) printf("%I64d\n", gao(a%t, b%t)); else printf("%I64d\n", gao(a%t, 0) + gao(t, b%t) + (a/t-b/t-1)*gao(t, 0)); }