A-逆序数
题目描述
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。比如一个序列为4 5 1 3 2, 那么这个序列的逆序数为7,逆序对分别为(4, 1), (4, 3), (4, 2), (5, 1), (5, 3), (5, 2),(3, 2)。
输入描述:
第一行有一个整数n(1 <= n <= 100000), 然后第二行跟着n个整数,对于第i个数a[i],(0 <= a[i] <= 100000)。
输出描述:
输出这个序列中的逆序数
示例1
输入
5
4 5 1 3 2
输出
7
思路 : 直接暴力就行
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
int p[maxn], n;
ll x, sum;
int main()
{
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> x;
sum += p[x];
for (int j = 1; j < x; j++) p[j]++;
}
cout << sum << endl;
return 0;
}
B-Big Water Problem
题目描述
给一个数列,会有多次询问,对于每一次询问,会有两种操作:
1:给定两个整数x, y, 然后在原数组的第x位置上加y;
2:给定两个整数l,r,然后输出数组从第l位加到第r位数字的和并换行
输入描述:
第一行有两个整数n, m(1 <= n, m <= 100000)代表数列的长度和询问的次数
第二行n个数字,对于第i个数字a[i],(0<=a[i]<=100000)。
接下来m行,每一行有三个整数f, x, y。第一个整数f是1或者是2,代表操作类型,如果是1,接下来两个数x,y代表第x的位置上加y,如果是2,则求x到y的和,保证数据合法。
输出描述:
输出每次求和的结果并换行
示例1
输入
10 2
1 2 3 4 5 6 7 8 9 10
1 1 9
2 1 10
输出
64
思路 :差分数组
AC代码 :
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
ll p[maxn], s[maxn], n, m, wi, ui, vi;
int main()
{
scanf("%lld%lld", &n, &m);
for (ll i = 1; i <= n; i++) {
scanf("%lld", &s[i]);
p[i] = s[i] + p[i - 1];
}
while (m--) {
scanf("%lld", &wi);
if (wi == 1) {
scanf("%lld%lld", &ui, &vi);
for (int j = ui; j <= n; j++) p[j] += vi;
}
else {
scanf("%lld%lld", &ui, &vi);
cout << p[vi] - p[ui - 1] << endl;
}
}
return 0;
}
C-字符串的问题
题目描述
有一个字符串 让你找到这个字符串 S 里面的子串T 这个子串 T 必须满足即使这个串的前缀 也是这个
串的后缀 并且 在字符串中也出现过一次的(提示 要求满足前后缀的同时也要在字符串中出现一次 只是前后缀可不行 输出最长满足要求字符串)
输入描述:
给出一个字符串 长度 1 到 1e6 全部是小写字母
输出描述:
如果找的到就输出这个子串T 如果不行就输出 Just a legend
示例1
输入
fixprefixsuffix
输出
fix
示例2
输入
abcdabc
输出
Just a legend
题目大意 : 有一个字符串, 如果他的前缀和后缀相等且该子串包含在字符串中间 (去掉头尾和)那么输出这个字符串,入股哦有多个,输出最长的那个
思路 :也是模拟,从前往后每次多加一个长度,看前缀后缀是否相等。然后在判断该子串是否包含在内,是就存下来,最后排个序输出最长的
AC代码 :
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
char c[maxn], s[maxn], t[maxn];
int ans = 1, flag, X, C, S;
string p[maxn];
string line, ch, str;
bool cmp (string a, string b) {
return a.size() > b.size();
}
int main()
{
cin >> line;
for (int i = 1; i < line.size() - 1; i++) c[X++] = line[i];
while (ans < line.size()) {
ch = line.substr(0, ans), str = line.substr(line.size() - ans, line.size() - 1);
if (ch == str) {
C = 0;
for (int i = 0; i < ch.size(); i++) s[C++] = ch[i];
if (strstr(c, s) != NULL || strcmp(c, s) == 0) {flag = 1; p[S++] = ch;}
}
ans++;
}
if (!flag) cout << "Just a legend" << endl;
else {
sort (p, p + S, cmp);
cout << p[0] << endl;
}
return 0;
}
D-集合问题
题目描述
给你a,b和n个数p[i],问你如何分配这n个数给A,B集合,并且满足:
若x在集合A中,则a-x必须也在集合A中。
若x在集合B中,则b-x必须也在集合B中。
输入描述:
第一行 三个数 n a b 1<=n<=1e5 1<=a,b<=1e9
第二行 n个数 p1 p2 p3...pn 1<=pi<=1e9
输出描述:
如果可以恰好分开就输出第一行 YES
然后第二行输出 n个数 分别代表pi 是哪个集合的 0 代表是A集合 1代表是B 集合
不行就输出NO
放在哪个集合都可以的时候优先放B
示例1
输入
4 5 9
2 3 4 5
输出
YES
0 0 1 1
示例2
输入
3 3 4
1 2 4
输出
NO
题目大意 :如果一个数在集合中,那么a - 该数或者 b - 该数必须也在集合中,如果输入的数符合该条件,输出集合分配情况
思路 : 二分模拟查找,因为A和B集合都可以存的情况下优先放B,所以我们直接先判断B集合是否可以存,如果不行,看A集合是否可以,如果还不行,直接break不成立
AC代码 :
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
ll p[maxn], n, ai, bi, u;
ll s[maxn], flag = 1;
bool vis[maxn];
ll lower(int m) {
ll l = 0, r = n - 1, mid;
while (l <= r) {
mid = (l + r) >> 1;
if (p[mid] > m) r = mid - 1;
else l = mid + 1;
if (p[mid] == m && !vis[mid]) return mid;
}
return n;
}
int main()
{
cin >> n >> ai >> bi;
for (int i = 0; i < n; i++) cin >> p[i];
sort (p, p + n);
for (int i = 0; i < n; i++) {
if (vis[i]) continue; // 没有查过
u = lower(bi - p[i]);
if (u != n && p[u] + p[i] == bi) // 找到了
s[u] = s[i] = 1, vis[u] = vis[i] = 1; // 标记并存进B
else {
u = lower(ai - p[i]);
if (u != n && p[u] + p[i] == ai)
s[u] = s[i] = 0, vis[u] = vis[i] = 1; // 标记并存A
else {flag = 0; break;} // A和B都不可存,直接跳出
}
}
if (!flag) cout << "NO" << endl;
else {
cout << "YES" << endl;
for (int i = 0; i < n - 1; i++) cout << s[i] << " ";
cout << s[n - 1] << endl;
}
return 0;
}
E-情人节的电灯泡
题目描述
情人节到了,小芳和小明手牵手,打算过一个完美的情人节,但是小刚偏偏也来了,当了一个明晃晃的电灯泡,小明很尴尬,就和小刚说,我交给你个任务,你完成了我俩就带你玩,否则你就回家吧。小刚很有当单身狗的觉悟,他坚决不想让小明过好情人节,同为单身狗的你能帮帮他吗?现在有一个n×n(1 <= n <= 1000)的格子,每一个格子都有一个电灯泡,可能是亮的,也可能是灭的(1代表亮, 0代表灭),现在有两种操作,一种是给你一个坐标,对于那个坐标上的灯泡,如果他是亮的,那么熄灭他,反之如果他是灭的,那么打开它。第二种操作是给你两个坐标,第一个坐标代表一个子矩阵的左上角,另一个坐标是右下角,请你求出当前子矩阵中有多少个灯泡是亮着的。燥起来吧!!!单身狗们!!!!
输入描述:
第一行两个整数,n(1 <= n <= 1000)和m(1 <= m <= 100000),分别代表正方形格子的边长和询问次数。
接下来n行,每一行有n个bool形数字(0或1),代表灯泡的状态。
接下来m行,每一行第一个数字f(1或2)代表操作的类型,如果f是1,那么接下来输入一个坐标(x, y)(1 <= x, y <= n),对于当前位置的灯泡状态进行改变,如果是2,那么接下来输入两个坐标(x1, y1)(1 <= x1, y1 <= n), (x2, y2)(1 <= x2, y2 <= n),确定子矩阵的位置,输出子矩阵中亮着的灯泡数量并换行。
输出描述:
对于每一个2操作,输出子矩阵中亮着的灯泡数量并换行。
示例1
输入
6 4
0 0 1 0 1 0
1 0 1 1 0 1
1 0 0 0 0 0
1 1 0 0 1 0
0 0 0 0 1 1
0 0 0 0 1 0
2 2 2 4 5
1 1 1
2 1 1 6 6
1 2 6
输出
4
14
思路 : 水题,直接模拟不会超时
AC代码 :
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 5;
bool p[maxn][maxn];
int n, m, ui, vi, u, v, wi;
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) cin >> p[i][j];
}
while (m--) {
cin >> wi;
if (wi == 1) {
cin >> ui >> vi;
p[ui][vi] = !p[ui][vi];
}
else {
int ans = 0;
cin >> ui >> vi >> u >> v;
for (int i = ui; i <= u; i++) {
for (int j = vi; j <= v; j++) {
if (p[i][j]) ans++;
}
}
cout << ans << endl;
}
}
return 0;
}
F-The Biggest Water Problem
题目描述
给你一个数,让他进行巴啦啦能量,沙鲁沙鲁,小魔仙大变身,如果进行变身的数不满足条件的话,就继续让他变身。。。直到满足条件为止。
巴啦啦能量,沙鲁沙鲁,小魔仙大变身:对于一个数,把他所有位上的数字进行加和,得到新的数。
如果这个数字是个位数的话,那么他就满足条件。
输入描述:
给一个整数数字n(1<=n<=1e9)。
输出描述:
输出由n经过操作满足条件的数
示例1
输入
12
输出
3
说明
12 -> 1 + 2 = 3
示例2
输入
38
输出
2
说明
38 -> 3 + 8 = 11 -> 1 + 1 = 2
思路 :把每一位表示出来直到个位
AC代码 :
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int main()
{
ll n;
cin >> n;
while (n >= 10) {
ll sum = 0, temp = n;
while (temp) {
sum += temp % 10;
temp /= 10;
}
n = sum;
}
cout << n << endl;
return 0;
}
G-送分啦QAQ
题目描述
幼儿园开学了,为了让小盆友们能尽可能的多的享受假期。校长大人决定让小盆友分批到校,至于每批学生来多少人由一个小傻子和一个小仙女负责,两个人轮番负责,校长会在最后的时候去查看工作进度,小傻子不想被别人嘲笑自己傻,小仙女要证明自己比小傻子聪明。所以她们回去争抢安排最后一名小盆友。每次安排的小盆友至少为1,至多为上一次安排的2倍。小仙女抢到了先手的机会。第一次安排小盆友不能直接安排所有的小盆友一起回校。
输入描述:
单组测试数据
输入一个整数n——n代表小盆的个数(n>=2&&n<=1e9)
输出描述:
输出获胜人的名字——“Xian”或者“Sha”
示例1
输入
3
输出
Sha
说明
(Fisrt)1 -> (Second) 2 || 2 - > 1 无论小仙女先送一个还是两个都会被小傻子获胜
示例2
输入
4
输出
Xian
说明
1 -> 2 -> 1 || 1 -> 1 -> 2 小仙女先送一个,小傻子无论送一个或者两个都会被小仙女取胜。
题目大意 :每次最少取一个,最多取上一次的2倍,小仙女先取,输入石子数量,输出获胜者
思路 : 有一个规律,满足斐波那契的石子,一定是谁先拿谁输
AC代码 :
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 50 + 5;
ll p[maxn], n, ans;
int main()
{
p[0] = 2, p[1] = 3;
for (int i = 2; i < 50; i++) p[i] = p[i - 1] + p[i - 2];
cin >> n;
ans = lower_bound (p, p + 50, n) - p;
if (p[ans] != n) cout << "Xian" << endl;
else cout << "Sha" << endl;
return 0;
}
H-Tree Recovery
题目描述
You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.
输入描述:
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+1, ... , Ab.
输出描述:
You need to answer all Q commands in order. One answer in a line.
示例1
输入
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
输出
4
55
9
15
题目大意 : 输入一个序列和查询次数,Q表示输出该区间的和,C表示该区间的数每个数 + 第三个数
思路 :线段树模板题
AC代码 :
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
struct node
{
ll l, r, lazy, len, w; // l表示左边界,r表示右边界,lazy用来更改区间,len表示区间大小
}tree[maxn * 4];
ll p[maxn], n, m;
char op;
void build(ll root, ll l, ll r) { // 建树
tree[root].l = l;
tree[root].r = r;
tree[root].lazy = 0;
tree[root].len = r - l + 1;
if (l == r) {
tree[root].w = p[l];
return ;
}
ll mid = (l + r) >> 1;
build(root << 1, l, mid);
build(root << 1 | 1, mid + 1, r);
tree[root].w = tree[root << 1].w + tree[root << 1 | 1].w;
}
void pushdown(ll root) { // 回溯
tree[root << 1].lazy += tree[root].lazy;
tree[root << 1 | 1].lazy += tree[root].lazy;
tree[root << 1].w += tree[root << 1].len * tree[root].lazy;
tree[root << 1 | 1].w += tree[root << 1 | 1].len * tree[root].lazy;
tree[root].lazy = 0;
}
void update(ll root, ll l, ll r, ll y) { // 修改区间
if (tree[root].l >= l && tree[root].r <= r) {
tree[root].lazy += y;
tree[root].w += tree[root].len * y;
return;
}
if (tree[root].l > r || tree[root].r < l)
return;
if (tree[root].lazy) pushdown(root);
update(root << 1, l, r, y);
update(root << 1 | 1, l, r, y);
tree[root].w = tree[root << 1].w + tree[root << 1 | 1].w;
}
ll query(ll root, ll l, ll r) { // 区间和
if (tree[root].l >= l && tree[root].r <= r)
return tree[root].w;
if (tree[root].l > r || tree[root].r < l)
return 0;
if (tree[root].lazy) pushdown(root);
return query(root << 1, l, r) + query(root << 1 | 1, l, r);
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> p[i];
build(1, 1, n);
while (m--) {
int ui, vi, wi;
cin >> op;
if (op == 'Q') {
cin >> ui >> vi;
cout << query(1, ui, vi) << endl;
}
else {
cin >> ui >> vi >> wi;
update(1, ui, vi, wi);
}
}
return 0;
}