前言
因为loceaner太菜了,他什么东西都不会
所以他打算学一个东西就记录一下
不过因为他很菜,所以他不会写原理……
而且,他希望在2019CSP之前不会断更
就酱紫,就是写给他自己的……因为他太菜了
基础算法
二维前缀和
//知识点:二维前缀和
/*
By:Loceaner
*/
#include
#include
#include
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
const int N = 1000;
int n, m;
int a[N][N], b[N][N];
int main() {
n = read(), m = read();
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
a[i][j] = read();
b[i][j] = a[i][j] + b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];
}
}
for(int i, u1, v1, u2, v2; i <= m; i++) {
u1 = read(), v1 = read(), u2 = read(), v2 = read();
cout << b[u2][v2] - b[u1 - 1][v2] - b[u2][v1 - 1] + b[u1 - 1][v1 - 1] << '\n';
}
return 0;
}
二维差分
//知识点:
/*
By:Loceaner
*/
#include
#include
#include
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
const int N = 1e3 + 11;
int n, m, a[N][N];
int main() {
n = read(), m = read();
for(int i = 1, u1, u2, v1, v2; i <= m; i++) {
u1 = read(), v1 = read(), u2 = read(), v2 = read();
a[u1][v1] += 1;
a[u2 + 1][v2 + 1] += 1;
a[u2 + 1][v1] -= 1;
a[u1][v2 + 1] -= 1;
}
//C[x1][y1] += x , C[x2 + 1][y2 + 1] += x , C[x1][y2 + 1] -= x , C[x2 + 1][y1] -= x;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
a[i][j] = a[i][j] + a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];;
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
cout << a[i][j] << ' ';
}
cout << '\n';
}
return 0;
}
排序不等式
给定3组数\(a, b, c\)
\(a[1]\)~\(a[n]\),\(b[1]\)~\(b[n]\),\(c[1]\)~\(c[n]\)
其中\(c[1]\)~\(c[n]\)是\(b[1]\)~\(b[n]\)的乱序排列
\(a[1]*b[n]+a[2]*b[n-1]+...<=a[1]*c[1]+a[2]*c[2]+...<=a[1]*b[1]+a[2]*b[2]+...\)
即:逆序和 <= 乱序和 <= 正序和
关于\(long\ long\)
在日常的题目中,一定要看好数据范围,如果会爆\(int\)的话,不要忘记开\(long long\)(无数次被坑!!)
高精度模板
最让人烦的就是高精度了,某些题并不难,但是要写高精。。烦\(\color{white}{(ps:板子来自lfd)}\)
namespace BigInteger {
struct Big_integer {
int d[10005], len;
void clean() {while(len > 1 and !d[len - 1]) len--;}
Big_integer() {memset(d, 0, sizeof d);len = 1;}
Big_integer(int num) {*this = num;}
Big_integer operator = (const char* num) {
memset(d, 0, sizeof d);
len = strlen(num);
for (int i = 0; i < len; i++) d[i] = num[len - 1 - i] - '0';
clean();
return *this;
}
Big_integer operator = (int num) {
char s[10005];
sprintf(s, "%d", num);
*this = s;
return *this;
}
Big_integer operator * (const Big_integer &b) const {
int i, j;
Big_integer c;
c.len = len + b.len;
for (j = 0; j < b.len; j++)
for (i = 0; i < len; i++)
c.d[i + j] += d[i] * b.d[j];
for (i = 0; i < c.len - 1; i++) c.d[i + 1] += c.d[i] / 10, c.d[i] %= 10;
c.clean();
return c;
}
Big_integer operator / (const int &b) {
int i, j, a = 0;
Big_integer c = *this;
for (i = len - 1; i >= 0; i--) {
a = a * 10 + d[i];
for (j = 0; j < 10; j++) if (a < b * (j + 1)) break;
c.d[i] = j;
a = a - b * j;
}
c.clean();
return c;
}
bool operator < (const Big_integer &b) const {
if (len != b.len) return len < b.len;
for (int i = len - 1; i >= 0; i--)
if (d[i] != b.d[i])
return d[i] < b.d[i];
return false;
}
string str() const {
char s[10005];
for (int i = 0; i < len; i++) s[len - 1 - i] = d[i] + '0';
return s;
}
};
istream& operator >> (istream& in, Big_integer &x) {
string s;
in >> s;
x = s.c_str();
return in;
}
ostream& operator << (ostream& out, const Big_integer &x) {
out << x.str();
return out;
}
}
using namespace BigInteger;
数据结构
单调栈
for(int i = 0; i < T.size(); i++){
while(! stk.empty() && stk.top() > T[i]){
stk.pop();
}
stk.push(A[i]);
}
单调队列
上经典的滑动窗口问题
#include
#include
#include
#include
#define maxn 1000100
using namespace std;
int q[maxn], a[maxn];
int n, k;
void getmin() {
int head = 0, tail = 0;
for (int i = 1; i < k; i++) {
while (head <= tail && a[q[tail]] >= a[i]) tail--;
q[++tail] = i;
}
for (int i = k; i <= n; i++) {
while (head <= tail && a[q[tail]] >= a[i]) tail--;
q[++tail] = i;
while (q[head] <= i - k) head++;
printf("%d ", a[q[head]]);
}
}
void getmax() {
int head = 0, tail = 0;
for (int i = 1; i < k; i++) {
while (head <= tail && a[q[tail]] <= a[i]) tail--;
q[++tail] = i;
}
for (int i = k; i <= n; i++) {
while (head <= tail && a[q[tail]] <= a[i]) tail--;
q[++tail] = i;
while (q[head] <= i - k) head++;
printf("%d ", a[q[head]]);
}
}
int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
getmin();
printf("\n");
getmax();
printf("\n");
return 0;
}
数学/数论
快速乘
//知识点:快速乘
/*
By:Loceaner
*/
#include
#include
#include
#define int long long
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
int a, b, p, ans;
int mul(int a, int b, int mod) {
int res = 0;
while(b) {
if(b & 1) res = (res + a) % mod;
a = (a + a) % mod;
b >>= 1;
}
return res % mod;
}
signed main() {
a = read(), b = read(), p = read();
ans = mul(a, b, p);
cout << ans << '\n';
return 0;
}
快速幂
//知识点:快速幂
/*
By:Loceaner
*/
#include
#include
#include
#define int long long
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
int a, b, p, ans;
int power(int a, int b, int mod) {
int res = 1;
while(b) {
if(b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res % mod;
}
signed main() {
a = read(), b = read(), p = read();
ans = power(a, b, p);
cout << ans << '\n';
return 0;
}
埃氏筛
void prime(int n) {
cnt = 0;
vis[0] = vis[1] = 1;
for(int i = 2; i <= n; ++i) {
if(!vis[i]) {
p[++cnt] = i;
for(int j = i * i; j <= n; j+=i) {
vis[j] = true;
}
}
}
}
线性筛
int vis[N], p[N], cnt;
void prepare() {
vis[0] = vis[1] = 1;
for(int i = 2; i <= n; i++) {
if(!vis[i]) p[++cnt] = i;
for(int j = 1; j <= cnt; j++) {
if(i * p[j] > n) break;
vis[i * p[j]] = 1;
if(i % p[j] == 0) break;
}
}
}