codeforces 有意思的思维题 1 ~ 15

1、给定数组,求满足i < j and ai * aj = i + j的数对数量

codeforces 1541B. Pleasant Pairs

原题链接:https://codeforces.com/problemset/problem/1541/B
在这里插入图片描述
思路

因为3 <= i + j <= 2 * n - 1
那么 3 <= ai * aj <= 2 * n - 1
换句话说,可以枚举aiaj的乘积,若(ai 存在 && aj 存在 && ai下标 + aj下标 == aiaj)那么 ans ++。

值得注意的一点是,因为题目写明了a数组每一个值一定不会重复,所以不需要考虑组合数的问题,同时,并不需要考虑顺序,因为并不要求 ai < aj。

代码

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define ull unsigned long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rim int m; scanf("%d", &m)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;
const int N = 200010; 
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};

ll a[N];
ll book[N];  // book[i] 表示值为 i 的下标是 book[i]

int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	rit;
	while (t --) {
		rin;
		MEM(book, 0);
		for (int i = 1; i <= n; ++ i) {
			cin >> a[i];
			book[a[i]] = i;
		}
		ll ans = 0;
		//枚举有可能的乘积
		for (int i = 3; i <= 2 * n - 1; ++ i) {
			int len = sqrt(i);
			for (int j = 1; j <= len; ++ j) {
				// if(ai 存在 && aj 存在 && ai下标 + aj下标 == ai*aj)
				if (i % j == 0 && j * j != i) {
					if (book[j] > 0 && book[i / j] > 0 
					    && book[j] + book[i / j] == i) {
						++ ans;
					}
				}
			}
		}
		cout << ans << endl;
	} 
	return 0;
}

2、第 i 步向前跳 i 步或后退 1 步

codeforces 1455B Jumps

原题链接:https://codeforces.com/problemset/problem/1455/B

在这里插入图片描述
在这里插入图片描述
大体题意
对于每一个数 x,可以确保在操作 x 次以内到达点 x,求最小操作数。
操作:①对于第 i 次操作,可以+i步
②对于第 i 次操作,可以往后退一步

思路
假如一直都是采取操作①,那么对于 x = 7,我们可以有以下讨论:
走第一步到达 1
走第二步到达 3
走第三步到达 6
走第四步到达 10

此时是第一次操过 x,我们可以发现我们一定可以通过把已经走过的其中一步变成后退就能到达7。
因为我们需要减掉10 - 7 = 3步,但本身包含了后退的那一步,所以我们需要把第二步变成后退即可。

结论:二分找到第一个走完后总步数会大于等于 x 的那一步的位置 p,假如总步数 == x,那么ans == p;假如总步数 == x + 1, 那么ans == p + 1; 假如总步数 >= x + 2,那么 ans == p。

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define ull unsigned long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rim int m; scanf("%d", &m)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;
const int N = 1000010; 
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};

ll a[N];
//二分找位置
int find(int n) {
	int l = 1, r = n;
	while (l <= r) {
		int mid = l + (r - l)  / 2;
		if (a[mid] < n) l = mid + 1;
		else r = mid - 1;
	}
	while (l >= 1 && a[l] > n) -- l;
	while (l <= n && a[l] < n) ++ l;
	//分类讨论
	if (a[l] == n) return l;
	else if (a[l] == n + 1) return l + 1;
	else return l;
}

int main() {
	freopen("D:\\in.txt", "r", stdin); 
	rit;
	for (int i = 1; i < N; ++ i) {
		a[i] = a[i - 1] + i;  //求步数前缀和
	}
	while (t --) {
		rin;
		cout << find(n) << endl;
	}
	return 0;
}

3、给两个点,求正方形的另两个点

原题链接:https://codeforces.com/problemset/problem/459/A
在这里插入图片描述
在这里插入图片描述
思路

题意要求正方形的边长必须与xy轴平行。
一开始以为平平无奇分类讨论同x、同y、对角线,但是数据范围包含负数,wa了一发,后面先把所有xy都加上110平移到第一象限,输出答案的时候再-110即可。

不平移的:
在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define ull unsigned long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rim int m; scanf("%d", &m)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;
const int N = 10000; 
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};

int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	int a, b, c, d;
	cin >> a >> b >> c >> d;
	//平移到第一象限
	a += 110;
	b += 110;
	c += 110;
	d += 110;
	int x, y, z, p;
	//同x
	if (a == c) {
		x = a + abs(b - d);
		y = min(b, d);
		z = a + abs(b - d);
		p = max(b, d);
	}
	//同y
	else if (b == d) {
		x = min(a, c);
		y = b + abs(a - c);
		z = max(a, c);
		p = b + abs(a - c);
	}
	//对角线
	else if (abs(a - c) == abs(b - d)) {
		if ((a < c && b < d) || (c < a && d < b)) {
			x = min(a, c);
			y = max(b, d);
			z = max(a, c);
			p = min(b, d);
		}
		else {
			x = min(a, c);
			y = min(b, d);
			z = max(a, c);
			p = max(b, d);
		}
	}
	//不合法
	else {
		cout << "-1";
		return 0;
	}
	x -= 110;
	y -= 110;
	z -= 110;
	p -= 110;
	cout << x << " " << y << " " << z << " " << p;
	return 0;
}

4、任选一些数,使得它们之和在w/2和w之间

codeforces A. Knapsack

原题链接:https://editor.csdn.net/md?articleId=120272340
在这里插入图片描述
在这里插入图片描述
这道题目很有意思

思路

首先剔除掉所有比w大的数,再将剩下的数从大到小排序获得a0、a1、a2……。
如果a0大于等于w / 2,那么直接输出结果;
否则sum去累加a0、a1、……直到sum >= w / 2.
如果sum把所有ai都加完还没到达 w / 2,说明不存在方案,输出-1。
这样贪心合理的原因是,如果需要用sum去累加ai,那么第一个数a0都不满 w/2了,那么后面的数每一次加起来是不会有超过 w 的现象,除非sum超过w/2之后还继续加。这就是w/2~w这个区间设计的妙的地方。
(同时需要注意是向上取整 (w + 1) / 2 ~ w )

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define ull unsigned long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rim int m; scanf("%d", &m)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;
const int N = 200010; 
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};

struct node {
	ll idx, num;
}; 

bool cmp(node a, node b) {
	return a.num < b.num;
}

node v[N];

void solve() {
	ll n, w;
	MEM(v, 0);
	int k = 0;
	cin >> n >> w;
	for (int i = 0; i < n; ++ i) {
		ll a;
		cin >> a;
		if (a <= w) v[k ++] = {i + 1, a};
	}
	sort(v, v + k, cmp);
	int i =  k - 1;  //排序是从小到大,所以这里从k - 1开始--
	if (i >= 0 && v[i].num >= (w + 1) / 2) cout << 1 << endl << v[i].idx << endl;
	else {
		ll sum = 0;
		vector<ll> ans;
		while (i >= 0 && sum < (w + 1) / 2) {
			sum += v[i].num;
			ans.push_back(v[i].idx);
			-- i;
		}
		if (sum < (w + 1) / 2 || sum == 0) cout << "-1" << endl;
		else {
			cout << ans.size() << endl;
			sort(ans.begin(), ans.end());
			for (int j = 0; j < ans.size(); ++ j) {
				cout << ans[j] << " ";
			}
			cout << endl;
		}
	}
}

int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	rit;
	while (t --) {
		solve();
	}
	return 0;
}

5、使二进制串不含有010、101序列

B. Subsequence Hate

原题链接:https://codeforces.com/problemset/problem/1363/B
在这里插入图片描述
在这里插入图片描述
思路

因为是序列,而不是子串,所以满足要求的必定是00000、11111、00011、11000这种类型的。

先统计0和1的全部个数分别为a、b。

全0、全1只需要ans = min(b, a)
剩下的00011、11000模型,我们可以直接扫一遍原串,枚举0、1转折点即可。

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define ull unsigned long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rim int m; scanf("%d", &m)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;
const int N = 10000; 
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};

string s;

int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	rit;
	while (t --) {
		cin >> s;
		ll a = 0, b = 0;
		for (int i = 0; i < s.size(); ++ i) {
			if (s[i] == '1') ++ a;
			else ++ b;
		}
		ll ans = min(a, b);  //全0或全1
		ll x = 0, y = 0;
		for (int i = 0; i < s.size(); ++ i) {
			if (s[i] == '0') ++ x;
			else ++ y;
			ans = min(ans, x + a - y);  //11000型
			ans = min(ans, y + b - x);  //00011型
		}
		cout << ans << endl;
	}
	return 0;
}

6、判断x能否被11、111、1111……表示出来

原题链接:https://codeforces.com/problemset/problem/1526/B
在这里插入图片描述
思路

除了11和111,其余的1111、11111……都可以被11和111表示出来。
而111 = 11 * 10 + 1,换而言之,111可以消掉一个余数1。
设 a = n % 11, b = n / 11, 若 a <= b / 10则存在方案,反之为NO。

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define ull unsigned long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rim int m; scanf("%d", &m)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;
const int N = 10000; 
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};

int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	rit;
	while (t --) {
		rln;
		ll a = n % 11, b = n / 11;
		if (a <= b / 10) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
}

7、若ai < ai+1,消掉其中一个,判断能否只剩一个数

C. Element Extermination

原题链接:https://codeforces.com/problemset/problem/1375/C

在这里插入图片描述
在这里插入图片描述
思路

方法①:只要a1 < an,即YES;反之就是NO
因为a2 ~ an-1这些数无论是大于还是小于an,都可以被a1或者an消掉。
方法②:从右边开始模拟,找出每一个递增区间的最高点(每一个递增区间的非最高点都可以被最高点消掉),假如这些最高点都大于 a1,则YES,反之NO。

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define ull unsigned long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rim int m; scanf("%d", &m)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;
const int N = 300010; 
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};

int a[N];
int b[N];
int c[N];

void solve() {
	rin;
	for (int i = 1; i <= n; ++ i) cin >> a[i];
	vector<int> v;
	a[0] = -INF;
	int r = a[n];
	for (int i = n - 1; i > 1; -- i) {
		if(a[i] > r) {
			v.push_back(r);
			r = a[i];
		}
	}
	v.push_back(r);
//	if (v[v.size() - 1] != r) v.push_back(r);
    // 3 4 5 6 1 2
	bool flag = true;
	for (int i = 0; i < v.size(); ++ i) {
		cout << "i == " << i << " v == " << v[i] << endl;
		if (v[i] < a[1]) flag = false;
	}
	if (flag) cout << "YES" << endl;
	else cout << "NO" << endl;
}

int main() {
	freopen("D:\\in.txt", "r", stdin); 
	rit;
	while (t --) {
		solve();
	}
	return 0;
}

8、已知 lcm(a,b) = x,求最小的max(a,b)

C. Fadi and LCM

原题链接:https://codeforces.com/problemset/problem/1285/C
在这里插入图片描述
思路:lcm分解+二进制枚举

将x的所有质因数分解出来,写成x = p1^a1 + p2 ^ a2 + …… + pn ^ an 的形式后,pi为质因子,ai为质因子的数目,因为题目要求最大值的最小值,所以对于两个数a、b来说,如果a已经具备p1^a1了,那么b就不必要具有p1这个质因子了,因为这样即不会影响到x的大小,又能保证此时的b最小。
(可以枚举的前提是x分解之后的pi^ai最多只有十几个)
所以就只剩下对x的所有pi^ai进行二进制枚举即可。

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define ull unsigned long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rim int m; scanf("%d", &m)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1000010; 
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};

ll x;
vector<ll> v;

int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	cin >> x;
	ll xx = x;
	ll len = sqrt(x);
	for (int i = 2; i <= len; ++ i) {
		if (x % i == 0) {
			ll num = 1;
			while (x > 1 && x % i == 0) {
				x /= i;
				num *= i;
			}
			v.push_back(num);
		}
	}
	if (x > 1) v.push_back(x);
	int n = v.size();
	ll ansa = INF, ansb = INF;
	for (int i = 0; i < 1 << n; ++ i) {
		ll a = 1, b = 1;
		for (int j = 0; j < n; ++ j) {
			if (i >> j & 1) a *= v[j];
		}
		b = xx / a; 
		if (max(a, b) < max(ansa, ansb)) {
			ansa = a;
			ansb = b;
		}
	}
	cout << ansa << ' ' << ansb;
	return 0;
}

9、随意交换字符,问最多能有几个二进制回文

原题链接:https://codeforces.com/problemset/problem/1251/B
在这里插入图片描述
在这里插入图片描述
思路

长度为奇数的必定能和自身交换成回文串,长度为偶数的只有四种可能,全1、全0、偶1+偶0、奇1+奇0.
可见,只有奇1+奇0不能通过交换自己变成回文串,并且它和长度为偶数的交换没有意义,只能和同样是奇1+奇0或者长度为奇数的交换。
故而统计奇1+奇0和长度为奇数的字符串数量再if-else一下即可。

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define ull unsigned long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rim int m; scanf("%d", &m)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;
const double eps = 0.0000000001;
const int N = 10000; 
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
string s;
int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	rit;
	while (t --) {
		rin;
		int a = 0, b = 0, x = 0, y = 0;
		for (int i = 0; i < n; ++ i) {
			cin >> s;
			if (s.size() % 2) ++ a;
			else ++ b; 
			for (int j = 0; j < s.size(); ++ j) {
				if (s[j] == '0') ++ x;
				else ++ y;
			}
		}
		if (a == 0 && (x % 2 == 1 || y % 2 == 1)) cout << n - 1 << endl;
		else cout << n <<endl;
	}
	return 0;
}

10、不超过20次猜出[2,100]中的一个未知数

原题链接:https://codeforces.com/problemset/problem/679/A
在这里插入图片描述
在这里插入图片描述
思路

(人生第一道交互题:是我们先输出一个数,才能读入yes / no)
合数的因子都可以拆成素数相乘,当然,也有可能是 8 =2 * 2 * 2这样的情况,所以还需要把2、3、5、7这些素数的平方也加入检测。
故而只需要去判断2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 + 4 9 25 49 这19个数中有多少个是未知数的因子,大于等于两个就是合数,反之就是素数。
所以这道题考的是合数拆分成素数。

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define ull unsigned long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rim int m; scanf("%d", &m)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;
const double eps = 0.0000000001;
const int N = 10000; 
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};

int primes[N], cnt = 0;
bool st[N];

void init() {
	int n = N - 2;
	for (int i = 2; i <= n; ++ i) {
		if (!st[i]) primes[cnt ++] = i;
		for (int j = 0; primes[j] <= n / i; ++ j) {
			st[primes[j] * i] = true;
			if (i % primes[j] == 0) break;
		}
	}
}

vector<int> v;

int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	init();
	for (int i = 0; i < cnt; ++ i) {
		if (primes[i] <= 50) v.push_back(primes[i]);
		int  a = primes[i] * primes[i];
		if (a <= 50) v.push_back(a);
	}
	int b = 0;
	for (int i = 0; i < v.size(); ++ i) {
		cout << v[i] << endl;
		string s;
		cin >> s;
		if (s == "yes") ++ b;
	}
	if (b >= 2) cout << "composite";
	else cout << "prime";
	return 0;
}

11、查区间能凑几次10

原题链接:https://codeforces.com/problemset/problem/1189/C
在这里插入图片描述
在这里插入图片描述
题目大意

直接看举例。

思路

因为满10都会cnt++,而剩余部分都会被积累下来,所以其实并不需要线段树,直接算前缀和里面有多少个10即可。

假如本题的si会超过10,那么只需要在读入ai的时候把si % 10读入即可。

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define ull unsigned long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rim int m; scanf("%d", &m)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;
const double eps = 0.0000000001;
const int N = 100010; 
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};

int a[N], s[N];

int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	rin;
	for (int i = 1; i <= n; ++ i) {
		cin >> a[i];
		s[i] = s[i - 1] + a[i];
	}
	rim;
	while (m --) {
		int a, b;
		cin >> a >> b;
		cout << (s[b] - s[a - 1]) / 10 << endl;
	}
	return 0;
}

12、能同时被2、3、5、7整除的最小n位数

原题链接:https://codeforces.com/problemset/problem/248/B

在这里插入图片描述
思路

拿 1 << i 去除 7 ,我们可以发现商是 142857 的不断循环,意味着可以每 6 位就是一个重复,打表后就可以发现规律了。

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define ull unsigned long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rim int m; scanf("%d", &m)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;
const double eps = 0.0000000001;
const int N = 100010; 
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};

char s[N];

int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	rin;
	if (n <= 2) cout << "-1";
	else if (n == 3) cout << "210";
	else {
		s[0] = '1';
		int j = n - 1;
		j -= 3;
		j %= 6;
		j += 3;
		if (j == 3) s[n - 2] = '5';
		else if (j == 4) s[n - 2] = '8';
		else if (j == 5) s[n - 2] = '7', s[n - 3] = '1';
		else if (j == 6) s[n - 2] = '2';
		else if (j == 7) s[n - 3] = '2';
		else s[n - 3] = '1', s[n - 2] = '1';
		for (int i = 1; i < n; ++ i) {
			if (s[i] == 0) s[i] = '0';
		}
		cout << s << endl;
	}
	return 0;
}

13、斜矩阵求路径和不同的个数

C. Celex Update

原题链接:https://codeforces.com/problemset/problem/1358/C
在这里插入图片描述
在这里插入图片描述
自己的思路

一开始以为找对角,以为从不同的地方来但是经过同样的对角后后面的情况是一样的,但很快发现题目要求的是路径和,就算后面走法有重复的,也维护不了总数,dp不了。

二是数据范围很大,T也很大,试了几个样例发现答案是路径和最大 - 路径和最小 + 1。
而路径和最大是先从起点向下走到底再向右走,路径和最小是先从起点向右走到边缘再向下走。

但是直接算路径和会发现是等差数列前n项和的前n项和,应该可以a但是很麻烦。接着发现两条路径相对应的位置是类似于+1 +2 + 3 + 3 + 3 + 2 + 1这样的关系,所以推一波公式即可ac。

看了题解有更妙的解法是,ans = (x2 - x1) * (y2 - y1)+ 1。
首先最大和和最小和之间的其他路径和一定可以达到,是因为可以通过向上或向下拐一个点让路径和 - 1 或 + 1。其次,最值路径和之差其实是元素个数,(x2 - x1) * (y2 - y1)计算的是矩形面积,同时也是该面积内的元素个数。
在这里插入图片描述

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define ull unsigned long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rim int m; scanf("%d", &m)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;

const int N = 10000; 
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};

int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	rit;
	while(t --) {
		ll a, b, x, y;
		cin >> a >> b >> x >> y;
		if (x == a || y == b) {
			cout << 1 << endl;
			continue;
		}
		ll p = min(x - a, y - b);
		ll q = max(x - a - 1, y - b - 1) - p;
		ll ans = (p + p * (p - 1) / 2) * 2 + q * p + 1;
		cout << ans << endl;
	}
	return 0;
}

14、只取叶节点,先取到x者胜

原题链接:https://codeforces.com/problemset/problem/1363/C
在这里插入图片描述
思路
一开始以为是考虑子树结点的奇偶,后面发现不对,如果x只剩下两个分支,当取到其中一个分支只有一个结点的时候,是不会有人取这个分支的,因为这样他必输。

所以僵持到最后,必然是 x 下面挂着两个叶节点(因为是无根树,所以直接拿x当根节点)。此时如果 n - 1 是奇数先手胜,反之后手胜。

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define ull unsigned long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rim int m; scanf("%d", &m)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;

const int N = 2010; 
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};

int h[N], e[N], ne[N], idx = 1;

void insert(int a, int b) {
	e[idx] = b;
	ne[idx] = h[a];
	h[a] = idx ++;
}

int dfs(int idx, int last) {
	int cnt = 1;
	for (int i = h[idx]; i != -1; i = ne[i]) {
		int j = e[i];
		if (j != last) {
			cnt += dfs(j, idx);
		}
	}
	return cnt;
}

int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	rit;
	while (t --) {
		int n, x;
		cin >> n >> x;
		MEM(h, -1);
		MEM(e, 0);
		MEM(ne, 0);
		idx = 1;
//		cout << "n == " << n << " x == " << x << endl;
		for (int i = 1; i < n; ++ i) {
			int a, b;
			cin >> a >> b;
			insert(a, b);
			insert(b, a);
//			 cout << a << " " << b << endl;
		}
		int cnt = 0;
		for (int i = h[x]; i != -1; i = ne[i]) {
			++ cnt;
		}
		if (cnt <= 1) cout << "Ayush" << endl;
		else {
			-- n;
			if (n % 2 == 1) cout << "Ayush" << endl;
			else cout << "Ashish" << endl;
		}
	}
	return 0;
}

15、按照给定偏移量移动数轴,问是否会有点重叠

A. Hilbert’s Hotel

原题链接:https://codeforces.com/problemset/problem/1344/A
在这里插入图片描述
在这里插入图片描述
思路

很显然,每k个数就是一组,拿5 5 5 1举例,当分别偏移下标为 0 1 2 3 的数时,获得的新位置是 5 6 7 4;
但是假如偏移量是 5 5 5 -1, 那么同样偏移 0 1 2 3 时得到的是 5 6 7 2,偏移 4 5 6 7将得到 9 10 11 6。
此时我们发现 6 重复出现了。
观察 5 6 7 2 可以发现 6 和 2 之间刚好差值是 n ,所以当下一批来偏移 4 5 6 7 时,7 会等于 2 + n = 6。

换句话说,我们把问题转换成了每相邻的 n 个新的位置里面会不会存在任意两个数的差值是 n 的倍数
但是直接暴力枚举会超时,可以把新的到的数都来 % n,这样来判断会不会有余数相同即可。

同时,如果负数太麻烦,可以将每个数同时加上 INF

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define ull unsigned long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rim int m; scanf("%d", &m)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;

const int N = 200010; 
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};

ll a[N];

int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	rit;
	while (t --) {
		rin;
		for (int i = 0; i < n; ++ i) {
			cin >> a[i];
			a[i] += i + INF;
			a[i] %= n;
		}
		sort(a, a + n);
		bool flag = true;
		for (int i = 1; i < n; ++ i) {
			if (a[i] == a[i - 1]) {
				flag = false;
				break;
			}
		}
		if (flag) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
}
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一些C语言初学者可能会觉得有趣的编程: 1. 猜数字游戏:编写一个程序,让用户猜一个范围内的随机生成的整数,直到猜中为止。程序应根据用户的猜测给出提示,告诉用户是猜大了还是猜小了。 2. 九九乘法表:编写一个程序打印出九九乘法表,即从1乘1到9乘9的所有结果。 3. 排序算法:实现常见的排序算法,如冒泡排序、选择排序或插入排序,并通过程序验证其正确性。 4. 计算器:编写一个简单的计算器程序,可以接受两个操作数和一个运算符,然后根据运算符执行相应的数学运算并输出结果。 5. 石头剪刀布游戏:编写一个石头剪刀布游戏的程序,让用户选择石头、剪刀或布,并与计算机进行对战,判断输赢并输出结果。 6. 简易登录系统:编写一个简单的登录系统,要求用户输入用户名和密码,并进行验证,如果匹配则输出登录成功,否则输出登录失败。 7. 生成斐波那契数列:编写一个程序,使用循环或递归方式生成斐波那契数列的前n项,并输出结果。 8. 统计字符个数:编写一个程序,接受一个字符串和一个字符,统计该字符在字符串中出现的次数,并输出结果。 9. 找出最大值和最小值:编写一个程序,接受一组整数输入,并找出其中的最大值和最小值,并输出结果。 10. 简易图书管理系统:编写一个简易的图书管理系统,包括图书的增加、删除、查询等功能,并可以将图书信息存储在文件中。 以上这些编程可以帮助初学者巩固基本的编程知识和技能,并提高对C语言的理解和应用能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值