思维
题:http://lx.lanqiao.cn/problem.page?gpid=T2908
题意:给定序列(a1,a2,……an),进行 m 次操作,p = 0,a1 ~ aq 降序排序,p = 1,aq ~ an 升序排序。
思路:如果是连续相同的操作,则取最大区间,可得两个操作是间或的,需要翻转的区间越来越小。根据操作去把数放好。
#include <iostream>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5 + 10, mod = 1e9 + 7, INF = 0x3f3f3f3f;
const double eps = 1e-8; //一般比小数点的位数至少多 2
int n, m;
PII stk[N];
int ans[N];
signed main()
{
scanf("%d%d", &n, &m);
int top = 0;
while (m--)
{
int p, q;
scanf("%d%d", &p, &q);
if (!p)
{
while (top && stk[top].x == 0)
q = max(q, stk[top--].y);
while (top >= 2 && stk[top - 1].y <= q)
top -= 2;
stk[++top] = {0, q};
}
else
if (top)
{
while (top && stk[top].x == 1)
q = min(q, stk[top--].y);
while (top >= 2 && stk[top - 1].y >= q)
top -= 2;
stk[++top] = {1, q};
}
}
int k = n, l = 1, r = n;
for (int i = 1; i <= top; ++i)
{
if (stk[i].x == 0)
while (r > stk[i].y && l <= r)
ans[r--] = k--;
else
while (l < stk[i].y && l <= r)
ans[l++] = k--;
if (l > r)
break;
}
if (top % 2)
while (l <= r)
ans[l++] = k--;
else
while (l <= r)
ans[r--] = k--;
for (int i = 1; i <= n; ++i)
printf("%d ", ans[i]);
return 0;
}
贪心
可反悔贪心
题:https://www.luogu.com.cn/problem/P1484
采用双向链表实现。
#include <iostream>
#include <cstdio>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <set>
#include <bitset>
//#include <unordered_set>
#include <memory.h>
#include <string>
#include <cstring>
#include <cmath>
//#include <random>
#include <map>
//#include <unordered_map>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define x first
#define y second
#define all(a) a.begin(), a.end()
//#define int long long
#define endl '\n'
#define bug(a) cout << a << " *bug1*" << endl
#define bugg(a, b) cout << a << " " << b << " *bug2*" << endl
#define buggg(a, b, c) cout << a << " " << b << " " << c << " *bug3*" << endl
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef pair<LL, int> PLI;
typedef pair<double, double> PDD;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
LL fastpow(LL b, LL k, LL p)
{
LL res = 1;
while (k)
{
if (k & 1)
res = res * 1LL * b % p;
b = b * 1LL * b % p;
k >>= 1;
}
//bug(res);
return res % p;
}
int lowbit(int x)
{
return x & -x;
}
const int N = 5e5+ 5, MOD = 1e9 + 7, INF = 0x3f3f3f3f;
const double eps = 1e-8; //一般比小数点的位数至少多 2
const double pi = 3.141592653589;
double func(double x, double y) // 评估函数
{
return 6 * pow(x, 7.0) + 8 * pow(x, 6.0) + 7 * pow(x, 3.0) + 5 * pow(x, 2.0) - y * x;
}
LL gcd(LL a, LL b)
{
return b == 0 ? a : gcd(b, a % b);
}
LL lcm(LL a, LL b)
{
return a / gcd(a, b) * b;
}
LL exgcd(LL a, LL b, LL &x, LL &y)
{
if (!b)
{
x = 1, y = 0;
return a;
}
LL d = exgcd(b, a % b, y, x);
y -= (a / b) * x;
return d;
}
LL wow[N];
int pre[N], nex[N];
bool v[N];
priority_queue<PLI> q;
inline void del(int u)
{
nex[pre[u]] = nex[u];
pre[nex[u]] = pre[u];
}
signed main()
{
IOS;
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; ++i)
{
cin >> wow[i];
q.push({wow[i], i});
pre[i] = i - 1;
nex[i] = i + 1;
}
LL ans = 0, res = 0;
while (m--)
{
auto t = q.top();
q.pop();
while (v[t.second])
{
t = q.top();
q.pop();
}
int u = t.second;
v[nex[u]] = v[pre[u]] = true;
ans += wow[u];
if (res >= ans)
break;
else
res = ans;
wow[u] = wow[nex[u]] + wow[pre[u]] - wow[u];
del(nex[u]);
del(pre[u]);
q.push({wow[u], u});
}
cout << res << endl;
return 0;
}
题:https://ac.nowcoder.com/acm/contest/32942/A
模拟退火
题:https://vjudge.net/contest/488791#problem/H
题意: F(x) = 6 * x^7 + 8 * x^6 + 7 * x^3 + 5 * x^2 - y * x (0 <= x <=100)。给出y的值,求F(x)的最小值。
#include <iostream>
#include <cstdio>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <set>
#include <bitset>
#include <unordered_set>
#include <memory.h>
#include <string>
#include <cstring>
#include <cmath>
#include <random>
#include <map>
#include <unordered_map>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define x first
#define y second
#define all(a) a.begin(), a.end()
#define int long long
#define endl '\n'
#define bug(a) cout << a << " *bug1*" << endl
#define bugg(a, b) cout << a << " " << b << " *bug2*" << endl
#define buggg(a, b, c) cout << a << " " << b << " " << c << " *bug3*" << endl
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
LL fastpow(LL b, LL k, LL p)
{
LL res = 1;
while (k)
{
if (k & 1)
res = res * 1LL * b % p;
b = b * 1LL * b % p;
k >>= 1;
}
//bug(res);
return res % p;
}
int lowbit(int x)
{
return x & -x;
}
const int N = 2e6 + 5, MOD = 1e9 + 7, INF = 0x3f3f3f3f;
const double eps = 1e-8; //一般比小数点的位数至少多 2
const double pi = 3.141592653589;
const double T0 = 1e5, TK = 1e-8, d = 0.98; //初始温度为高温,设置成一个大数;终止温度为低温,设置为一个接近于0的数;d是一个小于1但是非常接近于1的数
double func(double x, double y) // 评估函数
{
return 6 * pow(x, 7.0) + 8 * pow(x, 6.0) + 7 * pow(x, 3.0) + 5 * pow(x, 2.0) - y * x;
}
double simulateAnneal(double y)
{
double T = T0, x = 50.0; //初始值
double now = func(x, y); //当前状态
double nxt; //新状态
double ans = now; //最优解
int f[2] = {-1, 1};
while (T > TK)
{
double newx = x + f[rand() % 2] * T; //按概率改变x,温度越低概率越小
if (newx >= 0 && newx <= 100)
{
nxt = func(newx, y); //新状态
ans = min(ans, nxt); //在退火过程中维护遇到的所有解的最优值
double dE = now - nxt; //能量差
if (dE >= 0) //新状态更优就接受
{
now = nxt;
x = newx;
}
else
if (exp(dE / T) > rand()) //以一定概率接受
{
now = nxt;
x = newx;
}
}
T *= d; //降温
}
return ans;
}
signed main()
{
IOS;
int T;
cin >> T;
while (T--)
{
double y;
cin >> y;
cout << fixed << setprecision(4) << simulateAnneal(y) << endl;
}
return 0;
}
并查集
题:https://vjudge.net/problem/POJ-1182
题意:A吃B,B吃C,C吃A。有两个操作,op=1,x和y是一个物种,op=2,x吃y,根据前面的真话去判断当前的话是真是假,输出假话数量。
思路:根据维护到祖宗结点距离的并查集,可以知道,有三层集合,0、1、2。1吃0,2吃1,3吃2,由于这是一个食物环,所以3跟0是一类的,可以根据距离%3判断是哪个集合的,然后判断当前的话是真是假。
#include <iostream>
#include <cstdio>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <set>
#include <bitset>
//#include <unordered_set>
#include <memory.h>
#include <string>
#include <cstring>
#include <cmath>
//#include <random>
#include <map>
//#include <unordered_map>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define x first
#define y second
#define all(a) a.begin(), a.end()
//#define int long long
#define endl '\n'
#define bug(a) cout << a << " *bug1*" << endl
#define bugg(a, b) cout << a << " " << b << " *bug2*" << endl
#define buggg(a, b, c) cout << a << " " << b << " " << c << " *bug3*" << endl
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
LL fastpow(LL b, LL k, LL p)
{
LL res = 1;
while (k)
{
if (k & 1)
res = res * 1LL * b % p;
b = b * 1LL * b % p;
k >>= 1;
}
//bug(res);
return res % p;
}
int lowbit(int x)
{
return x & -x;
}
const int N = 5e4 + 5, MOD = 1e9 + 7, INF = 0x3f3f3f3f;
const double eps = 1e-8; //一般比小数点的位数至少多 2
const double pi = 3.141592653589;
double func(double x, double y) // 评估函数
{
return 6 * pow(x, 7.0) + 8 * pow(x, 6.0) + 7 * pow(x, 3.0) + 5 * pow(x, 2.0) - y * x;
}
int n, m;
int p[N], d[N];
int find(int x)
{
if (p[x] != x)
{
int t = find(p[x]);
d[x] += d[p[x]];
p[x] = t;
}
return p[x];
}
signed main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
p[i] = i;
int ans = 0;
while (m--)
{
int op, x, y;
scanf("%d%d%d", &op, &x, &y);
if (x > n || y > n)
ans++;
else
{
int px = find(x), py = find(y);
if (op == 1)
{
if (px == py && (d[x] - d[y]) % 3)
ans++;
else
if (px != py)
{
p[px] = py;
d[px] = d[y] - d[x];
}
}
else
{
if (px == py && (d[x] - d[y] - 1) % 3)
ans++;
else
if (px != py)
{
p[px] = py;
d[px] = d[y] + 1 - d[x];
}
}
}
}
printf("%d\n", ans);
return 0;
}
dp
题:https://ac.nowcoder.com/acm/contest/32907/I
#include <iostream>
#include <cstdio>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <set>
#include <bitset>
//#include <unordered_set>
#include <memory.h>
#include <string>
#include <cstring>
#include <cmath>
//#include <random>
#include <map>
//#include <unordered_map>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define x first
#define y second
#define all(a) a.begin(), a.end()
//#define int long long
#define endl '\n'
#define bug(a) cout << a << " *bug1*" << endl
#define bugg(a, b) cout << a << " " << b << " *bug2*" << endl
#define buggg(a, b, c) cout << a << " " << b << " " << c << " *bug3*" << endl
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
LL fastpow(LL b, LL k, LL p)
{
LL res = 1;
while (k)
{
if (k & 1)
res = res * 1LL * b % p;
b = b * 1LL * b % p;
k >>= 1;
}
//bug(res);
return res % p;
}
int lowbit(int x)
{
return x & -x;
}
const int N = 5e4 + 5, MOD = 1e9 + 7, INF = 0x3f3f3f3f;
const double eps = 1e-8; //一般比小数点的位数至少多 2
const double pi = 3.141592653589;
double func(double x, double y) // 评估函数
{
return 6 * pow(x, 7.0) + 8 * pow(x, 6.0) + 7 * pow(x, 3.0) + 5 * pow(x, 2.0) - y * x;
}
LL gcd(LL a, LL b)
{
return b == 0 ? a : gcd(b, a % b);
}
LL lcm(LL a, LL b)
{
return a / gcd(a, b) * b;
}
LL exgcd(LL a, LL b, LL &x, LL &y)
{
if (!b)
{
x = 1, y = 0;
return a;
}
LL d = exgcd(b, a % b, y, x);
y -= (a / b) * x;
return d;
}
LL n, t, dp[105][5205][105], w[105], v[105];
signed main()
{
scanf("%lld%lld", &n, &t);
for (int i = 1; i <= n; ++i)
scanf("%lld%lld", &w[i], &v[i]);
//这里用memset会超时
for (int i = 0; i <= n; ++i)
for (int j = 0; j <= 5200; ++j)
for (int k = 0; k <= t; ++k)
dp[i][j][k] = -INF;
for (int k = 0; k <= t; ++k) //把n=1的情况单独更新出来
{
//选第一张卡
if (k)
{
dp[1][2600 + 2 * v[1]][k] = w[1];
dp[1][2600 - 2 * v[1]][k] = w[1];
}
dp[1][2600 - v[1]][k] = w[1];
dp[1][2600 + v[1]][k] = w[1];
//不选第一张卡
dp[1][2600][k] = 0;
}
for (int i = 2; i <= n; ++i)
for (int j = 0; j <= 5200; ++j)
for (int k = 0; k <= t; ++k)
{
//不翻倍且不把第i张卡放入任何集合
dp[i][j][k] = dp[i - 1][j][k];
//翻倍且不把第i张卡放入任何集合的情况,不优,舍掉
//dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j][k - 1]);
//把第i张卡翻倍放入A集合
if (k >= 1 && j - 2 * v[i] >= 0)
dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j - 2 * v[i]][k] + w[i]);
//把第i张卡不翻倍放入A集合
if (j - v[i] >= 0)
dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j - v[i]][k] + w[i]);
//把第i张卡翻倍放入B集合
if (k >= 1 && j + 2 * v[i] <= 5200)
dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j + 2 * v[i]][k - 1] + w[i]);
//把第i张卡不翻倍放入B集合
if (j + v[i] <= 5200)
dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j + v[i]][k] + w[i]);
}
printf("%lld\n", dp[n][2600][t]);
return 0;
}
题:https://codeforces.com/contest/255/problem/C
题意:找到一个最长子序列p,q,p, q。(可以在给出的序列中任意删除元素)
#include <iostream>
#include <cstdio>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <set>
#include <bitset>
#include <unordered_set>
#include <memory.h>
#include <string>
#include <cstring>
#include <cmath>
#include <map>
#include <unordered_map>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define x first
#define y second
#define all(a) a.begin(), a.end()
//#define int long long
#define bug(a) cout << a << " *bug1*" << endl
#define bugg(a, b) cout << a << " " << b << " *bug2*" << endl
#define buggg(a, b, c) cout << a << " " << b << " " << c << " *bug3*" << endl
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
LL fastpow(LL b, LL k, LL p)
{
LL res = 1;
while (k)
{
if (k & 1)
res = res * 1LL * b % p;
b = b * 1LL * b % p;
k >>= 1;
}
//bug(res);
return res % p;
}
int lowbit(int x)
{
return x & -x;
}
const int N = 4e3 + 10, mod = 1e9 + 7, INF = 0x3f3f3f3f;
const double eps = 1e-8; //一般比小数点的位数至少多 2
int wow[N], dp[N][N];
signed main()
{
int n, ans = 0;
scanf("%d", &n);
for (int i = 1; i <= n; ++i) //子序列最后一个数是 i
{
scanf("%d", &wow[i]);
for (int j = 0, id = 0; j < i; ++j) //子序列倒数第二个数为 j
{
dp[i][j] = dp[j][id] + 1;
if (wow[i] == wow[j])
id = j; // id 记录前一个相等的数的位置
ans = max(ans, dp[i][j]);
}
}
printf("%d\n", ans);
return 0;
}
题:https://ac.nowcoder.com/acm/contest/30789/D
题意:给出N个数,问是否能从中选出一些数字,使得其加和为3600的倍数
#include <iostream>
#include <cstdio>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <set>
#include <bitset>
#include <unordered_set>
#include <memory.h>
#include <string>
#include <cstring>
#include <cmath>
#include <map>
#include <unordered_map>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define x first
#define y second
#define all(a) a.begin(), a.end()
//#define int long long
#define bug(a) cout << a << " *bug1*" << endl
#define bugg(a, b) cout << a << " " << b << " *bug2*" << endl
#define buggg(a, b, c) cout << a << " " << b << " " << c << " *bug3*" << endl
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
LL fastpow(LL b, LL k, LL p)
{
LL res = 1;
while (k)
{
if (k & 1)
res = res * 1LL * b % p;
b = b * 1LL * b % p;
k >>= 1;
}
//bug(res);
return res % p;
}
int lowbit(int x)
{
return x & -x;
}
const int N = 1e5 + 10, mod = 1e9 + 7, INF = 0x3f3f3f3f;
const double eps = 1e-8; //一般比小数点的位数至少多 2
int wow;
bool dp[N], cnt[N];
int n;
signed main()
{
int T;
scanf("%d", &T);
while (T--)
{
memset(dp, false, sizeof dp);
memset(cnt, false, sizeof cnt);
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
scanf("%d", &wow);
wow %= 3600;
if (!dp[0])
{
for (int j = 0; j < 3600; ++j)
if (dp[j] || !j)
cnt[(wow + j) % 3600] = true; //跟当前每个存在的数组成新值录入
for (int j = 0; j < 3600; ++j) //从cnt转存进dp
{
if (cnt[j])
dp[j] = true;
if (cnt[j])
cnt[j] = false;
}
}
}
if (!dp[0]) //判断是否能组成模为0的
printf("NO\n");
else
printf("YES\n");
}
return 0;
}
题:http://lx.lanqiao.cn/problem.page?gpid=T2900
题意:给定一个括号序列,要求尽可能少添加若干括号使之合法,求方案数。mod = 1e9 + 7。
思路:
左括号和右括号的插入是独立的,可以直接方案相乘起来。
插入左括号和插入右括号本质相同,将序列翻转后,每个字符也翻转即可。
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 5010, MOD = 1e9 + 7, INF = 0x3f3f3f3f;
const double eps = 1e-8; //一般比小数点的位数至少多 2
int n;
char str[N];
LL f[N][N];
LL calc()
{
memset(f, 0, sizeof f);
f[0][0] = 1;
for (int i = 1; i <= n; ++i)
if (str[i] == '(')
for (int j = 1; j <= n; ++j)
f[i][j] = f[i - 1][j - 1];
else
{
f[i][0] = (f[i - 1][0] + f[i - 1][1]) % MOD;
for (int j = 1; j <= n; ++j)
f[i][j] = (f[i - 1][j + 1] + f[i][j - 1]) % MOD;
}
for (int i = 0; i <= n; ++i)
if (f[n][i])
return f[n][i];
return -1;
}
signed main()
{
scanf("%s", str + 1);
n = strlen(str + 1);
LL l = calc();
reverse(str + 1, str + n + 1);
for (int i = 1; i <= n; ++i)
if (str[i] == '(')
str[i] = ')';
else
str[i] = '(';
LL r = calc();
printf("%lld\n", l * r % MOD);
return 0;
}
题:https://ac.nowcoder.com/acm/contest/11224/D
题意:按顺序选一些字符串拼接起来,求字符串最大和,且两个拼接的字符串中前者的尾要与后者的头相同。
思路:
#include <iostream>
#include <cstdio>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <set>
#include <bitset>
#include <unordered_set>
#include <memory.h>
#include <string>
#include <cstring>
#include <cmath>
#include <map>
#include <unordered_map>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define x first
#define y second
#define all(a) a.begin(), a.end()
//#define int long long
#define endl '\n'
#define bug(a) cout << a << " *bug1*" << endl
#define bugg(a, b) cout << a << " " << b << " *bug2*" << endl
#define buggg(a, b, c) cout << a << " " << b << " " << c << " *bug3*" << endl
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
LL fastpow(LL b, LL k, LL p)
{
LL res = 1;
while (k)
{
if (k & 1)
res = res * 1LL * b % p;
b = b * 1LL * b % p;
k >>= 1;
}
//bug(res);
return res % p;
}
int lowbit(int x)
{
return x & -x;
}
const int N = 2e5 + 10, MOD = 1e9 + 7, INF = 0x3f3f3f3f;
const double eps = 1e-8; //一般比小数点的位数至少多 2
int f[27];
signed main()
{
IOS;
int T;
cin >> T;
while (T--)
{
memset(f, 0, sizeof f);
int n;
cin >> n;
for (int i = 1; i <= n; ++i)
{
string s;
cin >> s;
f[s.back() - 'a'] = max(f[s.back() - 'a'], (int)s.size() + f[s[0] - 'a']);
}
int res = 0;
for (int i = 0; i < 26; ++i)
res = max(res, f[i]);
cout << res << endl;
}
return 0;
}
题:https://vjudge.net/contest/488040#problem/F
分治法
最近点对
题:https://ac.nowcoder.com/acm/contest/31222/A
题意:
f(i, j) =
(
i
,
j
)
2
(i, j)^2
(i,j)2 +
g
(
i
,
j
)
2
g(i, j)^2
g(i,j)2
g(i, j) = sum[j] - sum[i]
sum为前缀和数组
求最小f(i, j)
思路:转化为最近点对问题,下标作x,前缀和作y
#include <iostream>
#include <cstdio>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <set>
#include <bitset>
#include <unordered_set>
#include <memory.h>
#include <string>
#include <cstring>
#include <cmath>
#include <map>
#include <unordered_map>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define x first
#define y second
#define all(a) a.begin(), a.end()
//#define int long long
#define bug(a) cout << a << " *bug1*" << endl
#define bugg(a, b) cout << a << " " << b << " *bug2*" << endl
#define buggg(a, b, c) cout << a << " " << b << " " << c << " *bug3*" << endl
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
LL fastpow(LL b, LL k, LL p)
{
LL res = 1;
while (k)
{
if (k & 1)
res = res * 1LL * b % p;
b = b * 1LL * b % p;
k >>= 1;
}
//bug(res);
return res % p;
}
int lowbit(int x)
{
return x & -x;
}
const int N = 1e5 + 10, mod = 1e9 + 7, INF = 0x3f3f3f3f;
const double eps = 1e-8; //一般比小数点的位数至少多 2
struct Node
{
LL id, sum;
}node[N];
int tmp[N];
inline bool cmp(int a, int b)
{
return node[a].sum < node[b].sum;
}
inline LL dis(int i, int j)
{
return (node[i].id - node[j].id) * (node[i].id - node[j].id) + (node[i].sum - node[j].sum) * (node[i].sum - node[j].sum);
}
LL closest(int l, int r)
{
if (l == r)
return 1e18;
if (l + 1 == r)
return dis(l, r);
int mid = l + r >> 1;
LL mm = min(closest(l, mid), closest(mid + 1, r));
int tot = 0;
for (int i = l; i <= r; ++i)
if ((LL)(i - mid) * (i - mid) < mm)
tmp[tot++] = i;
sort(tmp, tmp + tot, cmp);
for (int i = 0; i < tot; ++i)
for (int j = i + 1; j < tot && (node[tmp[i]].sum - node[tmp[j]].sum) * (node[tmp[i]].sum - node[tmp[j]].sum) < mm; ++j)
mm = min(mm, dis(tmp[i], tmp[j]));
return mm;
}
signed main()
{
int n;
scanf("%d", &n);
node[0].sum = 0;
for (int i = 1; i <= n; ++i)
{
scanf("%lld", &node[i].sum);
node[i].sum += node[i - 1].sum;
node[i].id = i;
}
printf("%lld\n", closest(1, n));
return 0;
}
dfs
题:https://atcoder.jp/contests/abc236/tasks/abc236_d
题意:共有2N个人,编号为1-2N,现要人们两两配对,若编号为i的人想与编号为j的人配对,i必须小于j,i与j配对后获得亲和力B。所有人配对完成后亲和力分别为B1,B2…BN,总乐趣为B1⊕B2⊕…⊕BN。求所有配对组合中总乐趣的最大值。
#include <iostream>
#include <cstdio>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <set>
#include <bitset>
#include <unordered_set>
#include <memory.h>
#include <string>
#include <cstring>
#include <cmath>
#include <map>
#include <unordered_map>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define x first
#define y second
#define all(a) a.begin(), a.end()
//#define int long long
#define endl '\n'
#define bug(a) cout << a << " *bug1*" << endl
#define bugg(a, b) cout << a << " " << b << " *bug2*" << endl
#define buggg(a, b, c) cout << a << " " << b << " " << c << " *bug3*" << endl
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
LL fastpow(LL b, LL k, LL p)
{
LL res = 1;
while (k)
{
if (k & 1)
res = res * 1LL * b % p;
b = b * 1LL * b % p;
k >>= 1;
}
//bug(res);
return res % p;
}
int lowbit(int x)
{
return x & -x;
}
const int N = 3e5 + 10, mod = 1e9 + 7, INF = 0x3f3f3f3f;
const double eps = 1e-8; //一般比小数点的位数至少多 2
int n, m, ans = 0;
vector <int> t;
int wow[20][20];
bool vis[20];
void dfs(int p)
{
if (t.size() == n)
{
int tmp = t[0];
for (int i = 1; i < t.size(); ++i)
tmp ^= t[i];
ans = max(ans, tmp);
return ;
}
if (vis[p])
{
dfs(p + 1);
return ;
}
for (int i = p + 1; i < 2 * n; ++i)
{
if (!vis[i])
{
vis[p] = vis[i] = true;
t.push_back(wow[p][i]);
dfs(p + 1);
t.pop_back();
vis[p] = vis[i] = false;
}
}
}
signed main()
{
IOS;
cin >> n;
m = 2 * n;
for (int i = 0, x; i < m - 1; ++i)
for (int j = i + 1; j < m; ++j)
cin >> wow[i][j];
dfs(0);
cout << ans << endl;
return 0;
}
题:https://codeforces.com/problemset/problem/616/C
题意:给出n * m大小的只有‘ * ’和‘ . ’的矩阵,分别计算每一个’ * ‘的连通’ . ‘,当计算该’ * ‘时,可将该’ * ‘视为’ . ‘。
思路:首先预处理一下,每个’ . ‘的连通块计算出有多少并且标记,然后再分别处理每个’ * '四个方向的标记,如果该标记未出现过则加进ans。
#include <iostream>
#include <cstdio>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <set>
#include <bitset>
#include <unordered_set>
#include <memory.h>
#include <string>
#include <cstring>
#include <cmath>
#include <map>
#include <unordered_map>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define x first
#define y second
#define all(a) a.begin(), a.end()
//#define int long long
#define endl '\n'
#define bug(a) cout << a << " *bug1*" << endl
#define bugg(a, b) cout << a << " " << b << " *bug2*" << endl
#define buggg(a, b, c) cout << a << " " << b << " " << c << " *bug3*" << endl
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
LL fastpow(LL b, LL k, LL p)
{
LL res = 1;
while (k)
{
if (k & 1)
res = res * 1LL * b % p;
b = b * 1LL * b % p;
k >>= 1;
}
//bug(res);
return res % p;
}
int lowbit(int x)
{
return x & -x;
}
const int N = 1e3 + 10, mod = 1e9 + 7, INF = 0x3f3f3f3f;
const double eps = 1e-8; //一般比小数点的位数至少多 2
int n, m, tmp, cnt = 0;
char wow[N][N];
bool vis[N][N];
int hh[N][N], num[N * N];
map <int, int> mp;
void dfs(int x, int y)
{
hh[x][y] = cnt;
vis[x][y] = 1;
for (int i = 0; i < 4; ++i)
if (x + dx[i] >= 0 && x + dx[i] < n && y + dy[i] >= 0 && y + dy[i] < m && wow[x + dx[i]][y + dy[i]] == '.' && !vis[x + dx[i]][y + dy[i]])
{
tmp++;
dfs(x + dx[i], y + dy[i]);
}
}
signed main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; ++i)
scanf("%s", wow[i]);
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
if (wow[i][j] == '.' && !hh[i][j])
{
tmp = 1;
cnt++;
dfs(i, j);
num[cnt] = tmp;
}
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < m; ++j)
if (wow[i][j] == '*')
{
int ans = 0;
for (int k = 0; k < 4; ++k)
if (i + dx[k] >= 0 && i + dx[k] < n && j + dy[k] >= 0 && j + dy[k] < m && hh[i + dx[k]][j + dy[k]])
{
if (!mp[hh[i + dx[k]][j + dy[k]]])
{
ans += num[hh[i + dx[k]][j + dy[k]]];
mp[hh[i + dx[k]][j + dy[k]]]++;
}
}
printf("%d", (ans + 1) % 10);
mp.clear();
}
else
printf(".");
puts("");
}
return 0;
}
组合数学——隔板法
题:https://ac.nowcoder.com/acm/contest/30184/L
题意:给出每个数在 1~1000 之间的单调不增序列,其中有一些数字丢失了,找出有多少方案满足该序列要求,答案对1000000007取模。
#include <iostream>
#include <cstdio>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <algorithm>
#include <set>
#include <bitset>
#include <unordered_set>
#include <memory.h>
#include <string>
#include <cstring>
#include <cmath>
#include <map>
#include <unordered_map>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define x first
#define y second
#define all(a) a.begin(), a.end()
//#define int long long
#define bug(a) cout << a << " *bug1*" << endl
#define bugg(a, b) cout << a << " " << b << " *bug2*" << endl
#define buggg(a, b, c) cout << a << " " << b << " " << c << " *bug3*" << endl
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
LL fastpow(LL b, LL k, LL p)
{
LL res = 1;
while (k)
{
if (k & 1)
res = res * 1LL * b % p;
b = b * 1LL * b % p;
k >>= 1;
}
//bug(res);
return res % p;
}
const int N = 1e6 + 10, mod = 1e9 + 7, INF = 0x3f3f3f3f;
int a[N];
LL f[N];
void init() //预处理
{
f[0] = f[1] = 1;
for (int i = 2; i <= 1e6; ++i)
f[i] = (f[i - 1] * i) % mod;
}
LL C(int n, int m) //排列组合
{
if (m == 0)
return 1;
return (f[n] * fastpow(f[n - m] * f[m] % mod, mod - 2, mod) % mod) % mod; //乘法逆元
}
signed main()
{
init();
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
int cnt = 0, id = 0;
LL ans = 1;
a[0] = 1000;
for (int i = 1; i <= n; ++i)
{
if (!a[i])
cnt++; //小球
else
{
int n = cnt;
int m = a[id] - a[i] + 1; //盒子
id = i;
cnt = 0;
ans = ans * (C(n + m - 1, m - 1) % mod) % mod;
}
}
if (cnt) //末尾数处理
{
int n = cnt, m = a[id];
ans = ans * C(n + m - 1, m - 1) % mod;
}
printf("%lld\n", ans % mod);
return 0;
}
离散化 + 树状数组
题:https://www.acwing.com/problem/content/4319/
题意:
#include <iostream>
#include <cstdio>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <algorithm>
#include <set>
#include <bitset>
#include <unordered_set>
#include <memory.h>
#include <string>
#include <cstring>
#include <cmath>
#include <map>
#include <unordered_map>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define x first
#define y second
#define all(a) a.begin(), a.end()
#define int long long
#define bug(a) cout << a << " *bug1*" << endl
#define bugg(a, b) cout << a << " " << b << " *bug2*" << endl
#define buggg(a, b, c) cout << a << " " << b << " " << c << " *bug3*" << endl
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
LL fastpow(LL b, LL k, LL p)
{
LL res = 1;
while (k)
{
if (k & 1)
res = res * 1LL * b % p;
b = b * 1LL * b % p;
k >>= 1;
}
//bug(res);
return res % p;
}
int lowbit(int x)
{
return x & -x;
}
const int N = 1e6 + 10, mod = 1e9 + 7, INF = 0x3f3f3f3f;
int n, m;
int s[N];
int tr[N];
vector <int> nums;
void add(int x, int k) //树状数组修改操作
{
for (int i = x; i < N; i += lowbit(i))
tr[i] += k;
}
int sum(int x) //树状数组查询操作
{
int res = 0;
for (int i = x; i; i -= lowbit(i))
res += tr[i];
return res;
}
int get(int x) //二分获取离散化之后的下标
{
return lower_bound(all(nums), x) - nums.begin() + 1;
}
signed main()
{
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; ++i)
{
scanf("%lld", &s[i]);
s[i] += s[i - 1]; //前缀和
}
for (int i = 0; i <= n; ++i) //将所有前缀和以及后续询问用到的数值全部离散化
{
nums.push_back(s[i]);
nums.push_back(s[i] - m);
}
sort(all(nums));
nums.erase(unique(all(nums)), nums.end());
int res = 0;
add(get(s[0]), 1); //将 0 这个位置的前缀和加入树状数组
for (int i = 1; i <= n; ++i)
{
//sum(1000000) 整个值域上所有值的总个数
//sum(get(s[i]−m)) 表示所有 i 之前的前缀和中小于等于 get(s[i]−m) 的前缀和的个数
res += sum(1e6) - sum(get(s[i] - m)); //答案累加上树状数组中大于 sum[r] - t 的总个数
add(get(s[i]), 1); // sum[r] 这个位置的个数加上 1 ,方便后续的计算
//枚举右端点,右端点不减1,左端点减1
// sum(r) - sum(l-1) < t 即 sum(l-1) > sum(r) - t
}
printf("%lld\n", res);
return 0;
}