A题:分段筛法+二分搜索。首先预处理出区间[1, 10^8]中的所有素数,然后对于查询区间[a, b],只需要用区间[1, b]中的素数个数减去区间[1, a - 1]中的素数个数,显然可以二分得到。在筛选素数的过程中,并不是直接筛,而是采用分段筛法,即将区间[1, 10^8]划分为50个不相交的等长区间,分别筛选即可。
参考代码:
//#define SPJ #ifdef SPJ #include <bits/stdc++.h> #else #include <algorithm> #include <bitset> #include <cassert> #include <cmath> #include <complex> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <iostream> #include <list> #include <map> #include <numeric> #include <queue> #include <set> #include <sstream> #include <stack> #include <string> #include <vector> using namespace std; #endif #define dbg(x) cout << #x << " = " << x << endl #define dbg2(x,y) cout << #x << " = " << x << ", " << #y << " = " << y << endl #define dbg3(x,y,z) cout << #x << " = " << x << ", " << #y << " = " << y << ", " << #z << " = " << z << endl #define out(x) cout << (x) << endl #define out2(x,y) cout << (x) << " " << (y) << endl int prime[6000000]; int tot_prime = 0; bool vst[2000000 + 10]; void Get_prime_1(int M) {/* memset(vst, 0, sizeof(vst)); int i, j, k, Sq = 1 + (int)sqrt((M << 1) + 1.0); for(i = 3; i <= Sq; i += 2) { if( vst[i >> 1] ) continue; for(j = i * i, k = (i << 1); j <= ((M << 1) | 1); j += k) vst[j >> 1] = 1; } for(i = 1; i <= M; i ++) if( !vst[i] ) prime[tot_prime ++] = (i << 1) | 1;*/ int i, j; memset(vst, 0, sizeof(vst)); for(i = 3; i <= M; i += 2) { if( vst[i] ) continue; prime[tot_prime ++] = i; for(j = i << 1; j <= M; j += i) vst[j] = 1; } } void Get_prime_2(int l, int r) {/* memset(vst, 0, sizeof(vst)); int i, j, k; for(i = 1; prime[i] * prime[i] <= ((r << 1) | 1); i ++) { j = ((l << 1) | 1) / prime[i]; if( j % 2 == 0 ) j ++; j = j * prime[i]; for(k = prime[i] << 1; j <= ((r << 1) | 1); j += k) vst[(j >> 1) - l] = 1; } for(i = l; i <= r; i ++) { if( !vst[i - l] && tot_prime < 5900000 ) prime[tot_prime ++] = ((i << 1) | 1); }*/ memset(vst, 0, sizeof(vst)); int i, j; for(i = 0; prime[i] * prime[i] <= r; i ++) { j = l / prime[i] * prime[i]; if( j < l ) j += prime[i]; for(; j <= r; j += prime[i]) vst[j - l] = 1; } for(i = l; i <= r; i ++) { if( !vst[i - l] ) { prime[tot_prime ++] = i; } } } void init() { tot_prime = 0; prime[tot_prime ++] = 2; Get_prime_1(2000000); //printf("1: tot_prime = %d\n", tot_prime); for(int i = 2; i <= 50; i ++) { Get_prime_2(2000000 * (i - 1) + 1, 2000000 * i); //printf("tot_prime = %d\n", tot_prime); } //dbg(tot_prime); } int main() { //freopen("data.in", "r", stdin); //freopen("data.out", "w", stdout); init(); int N, a, b, l, r, m, pos, pos_2; while( scanf("%d %d", &a, &b) == 2 ) { N = b; l = 0, r = tot_prime - 1, pos = -1; while( l <= r ) { m = (l + r) >> 1; if( prime[m] <= N ) pos = m, l = m + 1; else r = m - 1; } N = a - 1; l = 0, r = tot_prime - 1, pos_2 = -1; while( l <= r ) { m = (l + r) >> 1; if( prime[m] <= N ) pos_2 = m, l = m + 1; else r = m - 1; } printf("%d\n", (pos + 1) - (pos_2 + 1)); } return 0; }
B题:线段树+动态规划。容易推导出动态规划递推表达式,即DP[i] = max{DP[j] + A[i]}, (A[j] < A[i], 1 <= j < i)。但是这样做复杂度相当高。此时,我们需要优化,我们可以先对数组的值进行非递减排序,相同的值按照索引的大小排序(这一点很有必要)。然后,建立以索引为区间的线段树,进行动态更新和查询。
参考代码:
//#define SPJ #ifdef SPJ #include <bits/stdc++.h> #else #include <algorithm> #include <bitset> #include <cassert> #include <cmath> #include <complex> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <iostream> #include <list> #include <map> #include <numeric> #include <queue> #include <set> #include <sstream> #include <stack> #include <string> #include <vector> using namespace std; #endif #define dbg(x) cout << #x << " = " << x << endl #define dbg2(x,y) cout << #x << " = " << x << ", " << #y << " = " << y << endl #define dbg3(x,y,z) cout << #x << " = " << x << ", " << #y << " = " << y << ", " << #z << " = " << z << endl #define out(x) cout << (x) << endl #define out2(x,y) cout << (x) << " " << (y) << endl const int maxN = 100000 + 2; typedef long long i64d; struct Seq { int idx; i64d val; inline void in(int &_idx) { scanf("%I64d", &val); idx = _idx; } inline bool operator<(const Seq &s) const { if( val != s.val ) return val < s.val; return idx > s.idx; } }; Seq A[maxN]; int nA; struct node { int l, r; i64d val; }; node tree[maxN * 5]; void build(int l, int r, int idx) { tree[idx].l = l; tree[idx].r = r; tree[idx].val = 0LL; if( l == r ) return ; int Mid = (l + r) >> 0x1; build(l, Mid, idx << 0x1); build(1 + Mid, r, (idx << 0x1) + 1); } void update(int idx, int &ip, i64d &val) { if( tree[idx].l == tree[idx].r ) { tree[idx].val = val; return ; } int Mid = (tree[idx].l + tree[idx].r) >> 0x1; if( ip <= Mid ) update(idx << 0x1, ip, val); else update(1 + (idx << 0x1), ip, val); tree[idx].val = max(tree[idx << 0x1].val, tree[(idx << 0x1) + 1].val); } i64d query(int l, int r, int idx) { if( l == tree[idx].l && tree[idx].r == r ) return tree[idx].val; int Mid = (tree[idx].l + tree[idx].r) >> 0x1; if( r <= Mid ) return query(l, r, idx << 0x1); else if( Mid < l ) return query(l, r, (idx << 0x1) + 1); else return max(query(l, Mid, idx << 0x1), query(1 + Mid, r, (idx << 0x1) + 1)); } i64d dp[maxN]; int main() { //freopen("data.in", "r", stdin); //freopen("data.out", "w", stdout); while( scanf("%d", &nA) == 1 ) { for(int i = 0; i < nA; ++i) A[i].in(i); sort(A, A + nA); build(0, nA - 1, 1); i64d tmp; for(int i = 0; i < nA; ++i) { tmp = query(0, A[i].idx, 1); //printf("tmp = %lld, idx = %d\n", tmp, A[i].idx); dp[i] = A[i].val + tmp; update(1, A[i].idx, dp[i]); } i64d ans = dp[0]; for(int i = 1; i < nA; ++i) if( dp[i] > ans ) ans = dp[i]; printf("%I64d\n", ans); } return 0; }
//#define SPJ #ifdef SPJ #include <bits/stdc++.h> #else #include <algorithm> #include <bitset> #include <cassert> #include <cmath> #include <complex> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <iostream> #include <list> #include <map> #include <numeric> #include <queue> #include <set> #include <sstream> #include <stack> #include <string> #include <vector> using namespace std; #endif #define dbg(x) cout << #x << " = " << x << endl #define dbg2(x,y) cout << #x << " = " << x << ", " << #y << " = " << y << endl #define dbg3(x,y,z) cout << #x << " = " << x << ", " << #y << " = " << y << ", " << #z << " = " << z << endl #define out(x) cout << (x) << endl #define out2(x,y) cout << (x) << " " << (y) << endl const int maxN = 1000000 + 10; char str[maxN]; int cnt[26]; int main() { //freopen("data.in", "r", stdin); //freopen("data.out", "w", stdout); int i, j; while( scanf("%s", str) == 1 ) { memset(cnt, 0, sizeof(cnt)); for(i = 0; str[i]; i ++) cnt[ str[i] - 'a' ] ++; for(i = 25; i >= 0; i --) if( cnt[i] & 1 ) { cnt[i] ++; break; } j = 0; for(i = 0; i < 26; i ++) if( cnt[i] & 1 ) { j = 1; putchar('a' + i); } if( j == 0 ) putchar('0'); putchar('\n'); } return 0; }
第1种思想:容易在读入数据的过程中,得到3个数,即min(最小的数),max(最大的数),sum(和),显然答案等于 sum - (max - min + 1) * (max + min) / 2,小数组高精度处理即可。
第2种思想:同样的,我们可以在输入的过程中得到3个数,即min(最小的数),max(最大的数),XOR(所有数的异或值),显然答案等于 XOR ^ [min ^ (min + 1) ^ ... ^ max],这里 ^ 表示异或运算。此时问题变成了需要求区间[min, max]所有的数的异或值,这是OJ上的一道陈题(链接),这里简单说下一种求解区间[a, b]所有的数的异或值的解法:
假设x是偶数,那么x ^ (x+1) 就等于1,也即x和(x+1)只有最低位不同。好了,我们会发现区间[a, b]是由大量的这样的x和x+1构成(除了边界情况)。
所以我们只需要从a和b的奇偶性入手即可,这里只考虑其中一种情况,即a是奇数,b是偶数,那么我们总可以把区间[a, b]划分为:
a, (a+1, a+2), (a+3, a+4), ..., (b-2, b - 1), b
显然中间有括号的两个数的异或值为1,假设这样的配对的数有y个,那么答案就是a ^ (y & 1) ^ b,不是吗?(其他情况可以参考着来。)
参考代码:
//#define SPJ #ifdef SPJ #include <bits/stdc++.h> #else #include <algorithm> #include <bitset> #include <cassert> #include <cmath> #include <complex> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <iostream> #include <list> #include <map> #include <numeric> #include <queue> #include <set> #include <sstream> #include <stack> #include <string> #include <vector> using namespace std; #endif #define dbg(x) cout << #x << " = " << x << endl #define dbg2(x,y) cout << #x << " = " << x << ", " << #y << " = " << y << endl #define dbg3(x,y,z) cout << #x << " = " << x << ", " << #y << " = " << y << ", " << #z << " = " << z << endl #define out(x) cout << (x) << endl #define out2(x,y) cout << (x) << " " << (y) << endl unsigned long long gao(unsigned long long l, unsigned long long r) { if( l == r ) return l; unsigned long long res = 0; if( l & 1LL ) { res ^= l; l ++; } if( !(r & 1LL) ) { res ^= r; r --; } if( l > r ) return res; unsigned long long last = ((r - l + 1LL) >> 1) & 1LL; return (res ^ last); } int main() { //freopen("data.in", "r", stdin); //freopen("data.out", "w", stdout); int n, i; unsigned long long mi, ma, res, ans; unsigned long long val; char ch; while( scanf("%d", &n) == 1 ) { //scanf("%llu", &val); while( (ch = getchar()) == ' ' || ch == '\n' ) ; val = ch - '0'; while( (ch = getchar()) >= '0' && ch <= '9' ) val = val * 10 + (ch - '0'); ans = mi = ma = val; for(i = 1; i < n; i ++) { //scanf("%llu", &val); while( (ch = getchar()) == ' ' || ch == '\n' ) ; val = ch - '0'; while( (ch = getchar()) >= '0' && ch <= '9' ) val = val * 10 + (ch - '0'); if( mi > val ) mi = val; if( ma < val ) ma = val; ans ^= val; } res = gao(mi, ma); //dbg3(mi, ma, res); printf("%llu\n", (res ^ ans)); } return 0; }
参考代码:
//#define SPJ #ifdef SPJ #include <bits/stdc++.h> #else #include <algorithm> #include <bitset> #include <cassert> #include <cmath> #include <complex> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <iostream> #include <list> #include <map> #include <numeric> #include <queue> #include <set> #include <sstream> #include <stack> #include <string> #include <vector> using namespace std; #endif #define dbg(x) cout << #x << " = " << x << endl #define dbg2(x,y) cout << #x << " = " << x << ", " << #y << " = " << y << endl #define dbg3(x,y,z) cout << #x << " = " << x << ", " << #y << " = " << y << ", " << #z << " = " << z << endl #define out(x) cout << (x) << endl #define out2(x,y) cout << (x) << " " << (y) << endl const int maxN = 100 + 2; vector<int> adj[maxN]; int sz[maxN]; int gcd(int a, int b) { if( b == 0 ) return a; return gcd(b, a % b); } void init() { for(int i = 100; i >= 1; i --) { for(int j = i; j >= 1; j --) if( gcd(i, j) == 1 ) { adj[i].push_back(j); } sz[i] = (int)adj[i].size(); } } int n, val, i, j, k; long long times[maxN]; long long res, tmp; char ch; int main() { //freopen("data.in", "r", stdin); //freopen("data.out", "w", stdout); init(); while( scanf("%d", &n) == 1 ) { memset(times, 0, sizeof(times)); k = 0; for(i = 0; i < n; i ++) { //scanf("%d", &val); while( (ch = getchar()) == ' ' || ch == '\n' ) ; val = ch - '0'; while( (ch = getchar()) >= '0' && ch <= '9' ) val = val * 10 + (ch - '0'); times[val] ++; if( k < val ) k = val; } res = times[1] * times[1]; for(i = k; i > 1; i --) { if( !times[i] ) continue; tmp = 0LL; times[i] <<= 1; for(j = 0; j < sz[i]; j ++) tmp += times[ adj[i][j] ]; res += times[i] * tmp; } printf("%lld\n", res); } return 0; }