// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用: intbsearch_1(int l, int r){ while (l < r) { int mid = l + r >> 1; if (check(mid)) r = mid; else l = mid + 1; } return l; } // 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用: intbsearch_2(int l, int r){ while (l < r) { int mid = l + r + 1 >> 1; if (check(mid)) l = mid; else r = mid - 1; } return l; }
int base = 10; //表示进制 vector<int> add(vector<int> &A, vector<int> &B){ if (A.size() < B.size()) returnadd(B, A); vector<int> res; int t = 0; for (int i = 0; i < A.size(); ++i) { t += A[i]; if (i < B.size()) t += B[i]; res.push_back(t % base); t /= base; } if (t) res.push_back(1); return res; }
voidsolve(){ string a, b; cin >> a >> b; int alen = a.size(), blen = b.size(); vector<int> A, B; for (int i = alen - 1; i >= 0; i--) A.push_back(a[i] - '0'); for (int i = blen - 1; i >= 0; --i) B.push_back(b[i] - '0'); vector<int> res = add(A, B); int rlen = res.size(); for (int i = rlen - 1; i >= 0; --i) printf(i == 0 ? "%d\n" : "%d", res[i]); }
boolcmp(vector<int> &A, vector<int> &B){ if (A.size() != B.size()) return A.size() > B.size(); for (int i = A.size() - 1; i >= 0; i--) if (A[i] != B[i]) return A[i] > B[i]; returntrue; }
vector<int> sub(vector<int> &A, vector<int> &B){ vector<int> res; int t = 0; for (int i = 0; i < A.size(); ++i) { t += A[i]; if (i < B.size()) t -= B[i]; res.push_back((t + base) % base); if (t < 0) t = -1; else t = 0; } while (res.size() > 1 && res.back() == 0) res.pop_back(); return res; }
voidsolve(){ string a, b; cin >> a >> b; int alen = a.size(), blen = b.size(); vector<int> A, B; for (int i = alen - 1; i >= 0; --i) A.push_back(a[i] - '0'); for (int i = blen - 1; i >= 0; --i) B.push_back(b[i] - '0'); vector<int> res; if (cmp(A, B)) res = sub(A, B); else { putchar('-'); res = sub(B, A); } int rlen = res.size(); for (int i = rlen - 1; i >= 0; --i) printf(i == 0 ? "%d\n" : "%d", res[i]); }
// res = A*b vector<int> mul(vector<int> &A, int b){ vector<int> res; int t = 0; // 进位 for (int i = 0; i < A.size() | t; ++i) { if (i < A.size()) t += A[i] * b; res.push_back(t % base); t /= base; } while (res.size() > 1 && res.back() == 0) res.pop_back(); return res; }
voidsolve(){ string a; int b; cin >> a >> b; vector<int> A; int alen = a.size(); for (int i = alen - 1; i >= 0; --i) A.push_back(a[i] - '0'); vector<int> res = mul(A, b); for (int i = res.size() - 1; i >= 0; --i) printf(i == 0 ? "%d\n" : "%d", res[i]); }
// A/b == res...r vector<int> div(vector<int> &A, int b, int &r){ vector<int> res; for (int i = A.size() - 1; i >= 0; --i) { r = r * base + A[i]; res.push_back(r / b); r %= b; } reverse(res.begin(), res.end()); while (res.size() > 1 && res.back() == 0) { res.pop_back(); } return res; }
voidsolve(){ string a; int b; int r = 0; vector<int> A; cin >> a >> b; int alen = a.size(); for (int i = alen - 1; i >= 0; --i) A.push_back(a[i] - '0'); vector<int> res = div(A, b, r); for (int i = res.size() - 1; i >= 0; --i) printf("%d", res[i]); printf("\n%d\n", r); }
int dp[MAXN << 1][32]; //从i开始,长度为2^j的区间中的最大值,写法的问题必须乘2不然RE int n; //区间长度 int a[MAXN]; //存放序列 int lg[MAXN]; //每个数以2为底的对数 (highbit) int m; //查询次数
voidpre(){ //预处理出以2为底的对数 for (int i = 1; i <= n; i++) lg[i] = (int)(log2(i)); }
voidinit(){ for (int i = 1; i <= n; i++) dp[i][0] = a[i]; for (int j = 1; j <= lg[n]; j++) for (int i = 1; i <= n; i++) dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]); }
voidsolve(){ n = read(), m = read(); for (int i = 1; i <= n; i++) a[i] = read(); pre(); init(); while (m--) { int l, r; //询问[l,r]这段区间的最大值 l = read(), r = read(); int k = lg[r - l + 1]; printf("%d\n", max(dp[l][k], dp[r - (1 << k) + 1][k])); } }
01分数规划
求解例如 k 个数,求得 (max/min)res=∑bi×xi∑ai×xi
化简一下式子得 y=∑(ai−res×bi)×xi=0
二分这个值,根据 ai−res×bi 去排序,取 k 个值之后判断是否为 0 。若去最大值,当值之和大于 0 说明 res 还能再取大,小于 0 说明 res 取小了。
GCC内置位运算函数__builtin
判断 n 的二进制中有多少个 1
__builtin_popcount(unsigned int n)
1 2
int n = 15; //二进制为1111 cout << __builtin_popcount(n) << endl; //输出4
判断 n 的二进制中 1 的个数的奇偶性
__builtin_parity(unsigned int n)
1 2 3 4
int n = 15; //二进制为1111 int m = 7; //111 cout << __builtin_parity(n) << endl; //偶数个,输出0 cout << __builtin_parity(m) << endl; //奇数个,输出1
判断 n 的二进制末尾最后一个 1 的位置,从 1 开始
__builtin_ffs(unsigned int n)
1 2 3 4
int n = 1; //1 int m = 8; //1000 cout << __builtin_ffs(n) << endl; //输出1 cout << __builtin_ffs(m) << endl; //输出4
判断 n 的二进制末尾后面 0 的个数,当 n 为 0 时,和 n 的类型有关
__builtin_ctz(unsigned int n)
1 2 3 4
int n = 1;//1 int m = 8;//1000 cout<<__builtin_ctzll(n)<<endl;//输出0 cout<<__builtin_ctz(m)<<endl;//输出3
返回前导 0 的个数
__builtin_clz (unsigned int x)
可以顺便求出第一个 1 出现的位置
整数三分
1 2 3 4 5 6 7 8 9 10 11 12 13 14
int l = 1, r = 100; while (l < r) { int lmid = l + (r - l) / 3; int rmid = r - (r - l) / 3; lans = f(lmid), rans = f(rmid); //求凹函数的极小值 if (lans <= rans) r = rmid - 1; else l = lmid + 1; //求凸函数的极大值 if (lans <= rans) l = lmid + 1; else r = rmid - 1; } cout << min(lans, rans) << endl; //求凹函数的极小值 cout << max(lans, rans) << endl; //求凸函数的极大值
// s[]是长文本,p[]是模式串,n是s的长度,m是p的长度 int n, m; int ne[N]; char s[M], p[N]; 求模式串的Next数组: for (int i = 2, j = 0; i <= m; i++) { while (j && p[i] != p[j + 1]) j = ne[j]; if (p[i] == p[j + 1]) j++ ; ne[i] = j; }
// 匹配 for (int i = 1, j = 0; i <= n; i++) { while (j && s[i] != p[j + 1]) j = ne[j]; if (s[i] == p[j + 1]) j ++ ; if (j == m) { j = ne[j]; // 匹配成功后的逻辑 } }
int n, m; char s[N], p[N]; int ne[N]; voidsolve(){ cin >> m >> p >> n >> s; ne[0] = -1; for (int i = 1, j = -1; i < m; i++) { while (j >= 0 && p[j + 1] != p[i]) j = ne[j]; if (p[j + 1] == p[i]) j++; ne[i] = j; }
for (int i = 0, j = -1; i < n; i++) { while (j != -1 && s[i] != p[j + 1]) j = ne[j]; if (s[i] == p[j + 1]) j++; if (j == m - 1) { cout << i - j << ' '; j = ne[j]; } } }
char s[MAXN]; int n; int decimal[MAXN]; //十进制数的位数 ll dp[MAXN]; //前i位压缩完最少的位数 int nxt[MAXN];
voidkmp(int len, char *s){ nxt[0] = nxt[1] = 0; for (int i = 1; i < len; i++) { int j = nxt[i]; while (j && s[i] != s[j]) j = nxt[j]; if (s[j] == s[i]) nxt[i + 1] = j + 1; else nxt[i + 1] = 0; } }
voidprework(){ for (int i = 0; i < 10; i++) decimal[i] = 1; for (int i = 10; i < 100; i++) decimal[i] = 2; for (int i = 100; i < 1000; i++) decimal[i] = 3; for (int i = 1000; i <= 8000; i++) decimal[i] = 4; for (int i = 1; i <= n; i++) dp[i] = i + 1; }
voidsolve(){ scanf("%s", s); n = strlen(s); prework(); for (int i = 0; i < n; i++) { kmp(n - i, s + i); for (int j = 1; j + i <= n; j++) { //j表示i和p之间的字符数量 int len = j - nxt[j]; if (j % len) { dp[j + i] = min(dp[j + i], dp[i] + 1 + j); } else { dp[j + i] = min(dp[j + i], dp[i] + decimal[j / len] + len); } } } printf("%d\n", dp[n]); }