一些因吹斯汀的题目记录

思维

题: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;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值