codeforces 思维题
- 1、给定数组,求满足i < j and ai * aj = i + j的数对数量
- 2、第 i 步向前跳 i 步或后退 1 步
- 3、给两个点,求正方形的另两个点
- 4、任选一些数,使得它们之和在w/2和w之间
- 5、使二进制串不含有010、101序列
- 6、判断x能否被11、111、1111……表示出来
- 7、若ai < ai+1,消掉其中一个,判断能否只剩一个数
- 8、已知 lcm(a,b) = x,求最小的max(a,b)
- 9、随意交换字符,问最多能有几个二进制回文
- 10、不超过20次猜出[2,100]中的一个未知数
- 11、查区间能凑几次10
- 12、能同时被2、3、5、7整除的最小n位数
- 13、斜矩阵求路径和不同的个数
- 14、只取叶节点,先取到x者胜
- 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;
}