这周就是刷cf和周末校赛,加油
12.14 周一
Codeforces Round #685 (Div. 2)
C. String Equality
这题一开始看到有交换的操作,联想到冒泡排序,就意识到其实是可以有任意的顺序的
所以题目给的字符串的顺序就不重要了,第二个操作相邻的问题也不用考虑的
但接下来怎么利用第二个操作就卡住了
有想到把每个字母统计出来,但觉得这个k非常非常的麻烦,只能连续k个才能变,不知道怎么处理这个k
然后就卡了一个小时没有什么思路,就看题解了
有思考但长时间没有什么思路就可以看题解,想不出没关系,积累经验,博客尤其好好总结没想出来的题目
题解有几个关键的点,也是之前一直卡住我的点
(1)如果目标字符串没有出现这个字符怎么整。我之前想的是那就不遍历了,这大大增加了思维难度,这弄得我都不知道该具体如何把
两个字符串的字符遍历一遍了。正确做法就是看作0个字符,和字符存在的1个字符,2个字符是等价了
这样就可以把字符不存在的情况归到一种通用的情况中。这和有些题把0看作跟节点的思想类似,把特殊情况归进来
(2)既然不存在看作0,那就可以每一个相同的字母比较了。这里关键的一点是,如果有多出来的字母而且是字母数是k的倍数,那就可以
加给下一个字母。下一个字母能用上就能用,不能用上还会给下下个字母。这就解决了我之前不知道怎么处理这个k的问题
可以从最开始的a开始想这个问题
(3)以后写完cf题后看题解的思路以及题解的代码。这个题解的代码就有我值得学习的地方。
比如变量的名称表示意义,判断的过程顺便处理
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
int n, k;
scanf("%d%d", &n, &k);
int have[30] = {0}, need[30] = {0};
getchar(); _for(i, 1, n) have[getchar() - 'a']++;
getchar(); _for(i, 1, n) need[getchar() - 'a']++;
int flag = 1;
REP(i, 0, 26)
{
if(have[i] < need[i] || (have[i] -= need[i]) % k)
{
flag = 0;
break;
}
have[i+1] += have[i];
}
if(flag) puts("Yes");
else puts("No");
}
return 0;
}
Educational Codeforces Round 98 (Rated for Div. 2)
赛前第四套cf题
A. Robot Program
注意矩阵的坐标和坐标系的坐标的区别,我在这里弄混了
我还有个地方理解错了,row是对于矩阵而言,而在坐标系中就是同一个x或同一个y
因为这些卡了一下
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", max(2 * x - 1, 2 * y - 1) + (x == y));
}
return 0;
}
C. Two Brackets
水题
本来想到用栈的,然后发现不需要
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int MAXN = 2e5 + 10;
char s[MAXN];
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%s", s);
int ans = 0, sum1 = 0, sum2 = 0;
REP(i, 0, strlen(s))
{
if(s[i] == '(') sum1++;
if(s[i] == '[') sum2++;
if(s[i] == ')' && sum1) sum1--, ans++;
if(s[i] == ']' && sum2) sum2--, ans++;
}
printf("%d\n", ans);
}
return 0;
}
明天做BD题,加油
12.15 周二
B. Toy Blocks
这题想出了一半,后一半卡住了,卡了2个小时,最后就看题解了
我自己推出要满足必须符合两个条件
sum能被n-1整除,而且sum / (n - 1) >= ma
但我不知道该怎么算要加的木块数
实际上直接从最后摆完的状态去考虑会简单很多,上两个条件也很容易推出
我原来想的是几块几块加上去直到符合条件,结果很难想
实际上这个两个条件可以直接推出结果的状态
我原来一直在纠结过程,没有考虑最后的结果是怎么样的
可以推出最后的高度k就是max(sum / (n-1), ma),前式向上取整
然后就算出最后所有的块数减去一开始的块数就可以了
答案那个向上取整的写法要学习
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
int ma, n;
ll sum;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
ma = sum = 0;
_for(i, 1, n)
{
int x; scanf("%d", &x);
ma = max(ma, x);
sum += x;
}
ll k = max((sum + n - 2) / (n - 1), (ll)ma);
printf("%lld\n", k * (n - 1) - sum);
}
return 0;
}
D. Radio Towers
最近一直在写思维题,也就是cf前几题
现在终于写了一道涉及到一些算法的题目了
这题中学到了很多
(1)首先要观察出一个递推关系。新加的村庄可以和前面的答案产生联系
把最后一个村覆盖到,剩下的部分就是前面的答案
于是有Fn = Fn-1 + Fn-3 + Fn-5……
看到这我以为要把以前的答案都搜一遍
然后后来发现这个式子可以再化简
Fn-3 + Fn-5…… = Fn-2
于是Fn = Fn-1 + Fn-2 这不就是斐波那契数列么
其实这种题一开始列前几项的分子就可以找一下规律,发现是斐波那契数列了
因此答案就是Fn / 2^n
(2)这道题涉及到MOD,又有除法,于是要用逆元
给的MOD是个质数,又于2^n互质
于是用费马小定理,y的逆元就是y^(MOD - 2)
然后官方题解建议涉及到MOD时可以另写函数
这里只有乘法可能爆int,所以可以全部设为int,乘法时多乘一个1ll
加法乘法可以都写个函数,就不用总是写个%MOD
(3)逆元一般就会涉及到快速幂。复习一下快速幂
cf题写完后一定要看官方题解和代码,学习一下,收获很大
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int MOD = 998244353;
const int MAXN = 2e5 + 10;
int f[MAXN];
int add(int a, int b) { return (a + b) % MOD; };
int mul(int a, int b) { return 1ll * a * b % MOD; }
int binpow(int a, int b)
{
int res = 1;
while(b)
{
if(b & 1) res = mul(res, a);
a = mul(a, a);
b >>= 1;
}
return res;
}
int main()
{
int n; scanf("%d", &n);
f[1] = f[2] = 1;
_for(i, 3, n)
f[i] = add(f[i-1], f[i-2]);
printf("%d\n", mul(f[n], binpow(binpow(2, n), MOD - 2)));
return 0;
}
决定好了
以后只用周三晚上和周五下午晚上来一次性解决作业
其他时候晚自习(自己来自习室)刷题
考前两周复习保证绩点
大计思修用来刷题
支撑我的一定是热爱,是内在驱动力
Codeforces Round #684 (Div. 2)
今晚来了一场模拟比赛,是赛前第五套题。以后晚上有空都可以来一次比赛加补题
今晚ac了3题,还不错吧。这是第二次模拟比赛。第一次ac了两题,有进步
A. Buy the String
比赛有点紧张过度了,导致a题中间有个字母打错了卡了一会儿
打完后可以检查一遍代码,不要太着急
精力集中且井然有序
赛后看题解发现还可以简化,只有换和不换两种可能
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
int n, c0, c1, h;
scanf("%d%d%d%d", &n, &c0, &c1, &h);
int ans = 0;
if(c0 > c1)
{
_for(i, 1, n)
{
int x; scanf("%1d", &x);
if(x == 1) ans += c1;
else ans += min(c0, c1 + h);
}
}
else
{
_for(i, 1, n)
{
int x; scanf("%1d", &x);
if(x == 0) ans += c0;
else ans += min(c1, c0 + h);
}
}
printf("%d\n", ans);
}
return 0;
}
B. Sum of Medians
这题我是看样例选的数猜出算法的
发现样例选的中位数在数列中的间隔都一样
然后发现显然是贪心
用上了下午刚学的向上取整
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int MAXN = 2e5 + 10;
int a[MAXN];
int main()
{
int T; scanf("%d", &T);
while(T--)
{
int n, k;
scanf("%d%d", &n, &k);
_for(i, 1, n * k) scanf("%d", &a[i]);
long long ans = 0;
int t = n - (n + 1) / 2;
int p = n * k - t;
int cnt = k;
while(cnt--) ans += a[p], p -= t + 1;
printf("%lld\n", ans);
}
return 0;
}
C1. Binary Table (Easy Version)
一开始毫无思路
突然想到可以每一个2乘2的矩阵的暴力变成0
然后就对2乘2矩阵的每一种情况分类讨论,看似多,其实可以相互转化,最后并不是很多,拿笔演算
这题码量挺大,我中间还有点迷要不要继续写,坚持写下去最后ac了,不错不错
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
#define search _for(i, x, x + 1) _for(j, y, y + 1)
using namespace std;
const int MAXN = 110;
const int MAXM = 6e4 + 10;
int a[MAXN][MAXN], n, m, cnt;
vector<int> ans[MAXM];
void add_ans(int x, int y, int xx, int yy)
{
cnt++; ans[cnt].clear();
search
if(i != xx || j != yy)
{
a[i][j] ^= 1;
ans[cnt].push_back(i);
ans[cnt].push_back(j);
}
}
void deal3(int x, int y)
{
search
if(!a[i][j])
{
add_ans(x, y, i, j);
return;
}
}
void deal2(int x, int y)
{
int x1 = 0, y1, x2, y2;
search
if(a[i][j])
{
if(!x1) x1 = i, y1 = j;
else x2 = i, y2 = j;
}
int flag = abs(x1 - x2) + abs(y1 - y2);
search
if((flag == 1 && !a[i][j]) || (flag == 2 && a[i][j]))
{
add_ans(x, y, ((i-x)^1)+x, ((j-y)^1)+y);
deal3(x, y);
return;
}
}
void deal1(int x, int y)
{
search
if(a[i][j])
{
add_ans(x, y, ((i-x)^1)+x, ((j-y)^1)+y);
deal2(x, y);
return;
}
}
void deal4(int x, int y)
{
add_ans(x, y, x, y);
deal1(x, y);
}
int count(int x, int y)
{
int res = 0;
search
res += a[i][j];
return res;
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
cnt = 0;
scanf("%d%d", &n, &m);
_for(i, 1, n)
_for(j, 1, m)
scanf("%1d", &a[i][j]);
_for(i, 1, n - 1)
_for(j, 1, m - 1)
{
int num = count(i, j);
if(num == 1) deal1(i, j);
if(num == 2) deal2(i, j);
if(num == 3) deal3(i, j);
if(num == 4) deal4(i, j);
}
printf("%d\n", cnt);
_for(i, 1, cnt)
{
REP(j, 0, 6)
printf("%d ", ans[i][j]);
puts("");
}
}
return 0;
}
C2. Binary Table (Hard Version)
赛后补题
看了题解,没我想的那么难。
必须要少于nm个操作,其实暗含着提示
也就是每次操作至少去掉一个1
于是我们可以一行一行的去,一列一列的去
从最下面一行开始,遍历一遍,有1就把它去掉,去完行数减一
最后剩下2乘2
就可以用我之前easy version的方法(用笔手算出多种情况)
其实不难,但我当时就是没想到这个思路
我想不到是因为三个同时变化太复杂了,有多种可能
而这种思路就是把三个变化化成一个变化,大大简化
同时把全部变为0转化为一行一行为0,也简化了
把二维问题简化成一维问题
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
#define search _for(i, x, x + 1) _for(j, y, y + 1)
using namespace std;
const int MAXN = 110;
const int MAXM = 6e4 + 10;
int a[MAXN][MAXN], n, m, cnt;
vector<int> ans[MAXM];
void add_ans(int x, int y, int xx, int yy)
{
cnt++; ans[cnt].clear();
search
if(i != xx || j != yy)
{
a[i][j] ^= 1;
ans[cnt].push_back(i);
ans[cnt].push_back(j);
}
}
void deal3(int x, int y)
{
search
if(!a[i][j])
{
add_ans(x, y, i, j);
return;
}
}
void deal2(int x, int y)
{
int x1 = 0, y1, x2, y2;
search
if(a[i][j])
{
if(!x1) x1 = i, y1 = j;
else x2 = i, y2 = j;
}
int flag = abs(x1 - x2) + abs(y1 - y2);
search
if((flag == 1 && !a[i][j]) || (flag == 2 && a[i][j]))
{
add_ans(x, y, ((i-x)^1)+x, ((j-y)^1)+y);
deal3(x, y);
return;
}
}
void deal1(int x, int y)
{
search
if(a[i][j])
{
add_ans(x, y, ((i-x)^1)+x, ((j-y)^1)+y);
deal2(x, y);
return;
}
}
void deal4(int x, int y)
{
add_ans(x, y, x, y);
deal1(x, y);
}
int count(int x, int y)
{
int res = 0;
search
res += a[i][j];
return res;
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
cnt = 0;
scanf("%d%d", &n, &m);
_for(i, 1, n)
_for(j, 1, m)
scanf("%1d", &a[i][j]);
while(n > 2)
{
_for(j, 1, m - 1)
if(a[n][j])
add_ans(n - 1, j, n, j + 1);
if(a[n][m]) add_ans(n - 1, m - 1, n, m - 1);
n--;
}
while(m > 2)
{
_for(i, 1, n - 1)
if(a[i][m])
add_ans(i, m - 1, i + 1, m);
if(a[n][m]) add_ans(n - 1, m - 1, n - 1, m);
m--;
}
int num = count(1, 1);
if(num == 1) deal1(1, 1);
if(num == 2) deal2(1, 1);
if(num == 3) deal3(1, 1);
if(num == 4) deal4(1, 1);
printf("%d\n", cnt);
_for(i, 1, cnt)
{
REP(j, 0, 6)
printf("%d ", ans[i][j]);
puts("");
}
}
return 0;
}
12.16 周三
Codeforces Round #682 (Div. 2)
赛前第6套cf题
上午打了模拟比赛
这次我太水了,只过了a题,bc题硬是没想出来
还很菜,认真补题
A. Specific Tastes of Andre
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
int n; scanf("%d", &n);
_for(i, 1, n) printf("1 ");
puts("");
}
return 0;
}
B. Valerii Against Everyone
其实思路很简单,可我就是没想到
一开始想到二进制,一堆一堆数不好比较,也不知道怎么遍历
看了题解发现原来可以字串长度就为1,看有没有相同元素就可以了
先想到如果序列长度为1时,两个相等就可以
再想如不存在时,那么一定不行
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
map<int, bool> vis;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
vis.clear();
int ans = 0;
int n; scanf("%d", &n);
_for(i, 1, n)
{
int x; scanf("%d", &x);
if(!vis[x]) vis[x] = 1;
else ans = 1;
}
if(ans) puts("YES");
else puts("NO");
}
return 0;
}
C. Engineer Artem
受昨天矩阵的一题影响,想一行一行地处理或者一列一列的处理
发现比较麻烦,因为这里一行处理完之后并不能完全扔掉,思维很复杂
题解很骚,处理成棋盘,每个相邻的都是一奇一偶
这思路太清奇了
只能说我做的题还太少吧
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int MAXN = 110;
int a[MAXN][MAXN], n, m;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
_for(i, 1, n)
_for(j, 1, m)
{
scanf("%d", &a[i][j]);
if((i + j) & 1)
{
if((a[i][j] & 1) == 0) a[i][j]++;
}
else
{
if(a[i][j] & 1) a[i][j]++;
}
}
_for(i, 1, n)
{
_for(j, 1, m)
printf("%d ", a[i][j]);
puts("");
}
}
return 0;
}
课内的oj题和作业可以集中时间一起做,其他时间留出整块的时间编程
另外题目可以存在脑子里想思路,有空就想,想通了ac就是写个程序的事情
最近调整时间管理方式,真的多了很多时间来刷oj,太爽了
保持这种时间分配的方式
Codeforces Round #683 (Div. 2, by Meet IT)
今天晚上来一套。这是赛前第七套了。独立做出abcd,爽
A. Add Candies
只有相对关系有用,关注差值就好
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
int n; scanf("%d", &n);
printf("%d\n", n);
_for(i, 1, n) printf("%d ", i);
puts("");
}
return 0;
}
B. Numbers Box
发现一个负号可以随意传递
所以分奇数个负号和偶数个负号就行 可以发现0不影响答案
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int MAXN = 15;
int a[MAXN][MAXN], n, m;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
int sum = 0, cnt = 0, mi = 1e9;
scanf("%d%d", &n, &m);
_for(i, 1, n)
_for(j, 1, m)
{
scanf("%d", &a[i][j]);
if(a[i][j] < 0) cnt++;
mi = min(mi, abs(a[i][j]));
sum += abs(a[i][j]);
}
if(cnt & 1) printf("%d\n", sum - mi * 2);
else printf("%d\n", sum);
}
return 0;
}
C. Knapsack
看完以为01背包,然后发现体积可以到10的18次方,肯定不能背包
不存在一个物品就可以的情况下
把小于一半体积的物品求和就行,只要大于一半体积说明肯定可以
我这里输入到一半break了,wa了几次
以后要注意,退出时输入要输入完
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 10;
ll w, key;
int a[MAXN], n, m;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d%lld", &n, &w);
key = (w + 1) / 2;
m = 0; int t;
_for(i, 1, n)
{
scanf("%d", &a[i]);
if(key <= a[i] && a[i] <= w)
{
m = 1;
t = i;
}
}
if(m)
{
printf("%d\n%d\n", m, t);
continue;
}
ll sum = 0;
int flag = 0;
_for(i, 1, n)
if(a[i] < key)
{
sum += a[i];
m++;
if(sum >= key)
{
flag = 1;
break;
}
}
if(!flag) puts("-1");
else
{
printf("%d\n", m);
_for(i, 1, n)
if(a[i] < key)
{
printf("%d ", i);
if(--m == 0) break;
}
}
}
return 0;
}
D. Catching Cheaters
D题终于涉及到点算法了
一开始挺懵逼的
然后发现题目那个式子可以化简
其实就是每个串相同的个数减去不同的个数
那么dp就完事,从之前最长公共子序列的dp拓展开就好
可以说是最长公共子序列的拓展变形
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int MAXN = 5000 + 10;
int f[MAXN][MAXN], n, m;
char a[MAXN], b[MAXN];
int main()
{
scanf("%d%d", &n, &m);
scanf("%s%s", a + 1, b + 1);
int ans = 0;
_for(i, 1, n)
_for(j, 1, m)
{
if(a[i] == b[j]) f[i][j] = max(f[i-1][j-1], 0) + 2;
else f[i][j] = max(max(f[i-1][j], f[i][j-1]), 0) - 1;
ans = max(ans, f[i][j]);
}
printf("%d\n", ans);
return 0;
}
12.17 周四
其实目前D题对我来说也没有多难。今天可以多做一些D题
D. Circle Game
看了题感觉是y=x这条线一直走,但不知道怎么证明
ac后看题解,题解也没说为什么
我的写法比官方题解好一些,不需要枚举,可以直接算出来,开根号
注意pow的结果是double,double可以很大,但会损失精度
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
int d, k;
scanf("%d%d", &d, &k);
int n = sqrt(pow(d, 2) / (2 * pow(k, 2)));
if(pow(n * k, 2) + pow(n * k + k, 2) > pow(d, 2)) puts("Utkarsh");
else puts("Ashish");
}
return 0;
}
D. Sequence and Swaps
这题其实思路蛮快的,但后来一直WA
突然发现是要额外判断一下数据相等的情况
这个时候这片数据的中间部分就不要交换了,我多算了这一块
写了个O(n)的算法,应该是比官方题解的n要优的(我完全没想到dp)
我找到问题补上了一个循环,以为复杂度变成了n方
其实算了一下不是,依然是n
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int MAXN = 500 + 10;
int a[MAXN], n, x;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &x);
_for(i, 1, n) scanf("%d", &a[i]);
int ans = 0, p = 1;
_for(i, 1, n - 1)
{
if(a[i] <= a[i+1]) continue;
int flag = 1;
_for(j, p, i)
{
if(a[j] > x)
{
p = j;
break;
}
if(j == i) flag = 0;
}
if(!flag) { ans = -1; break; }
if((p == i && x <= a[i+1]) || (p != i && a[i-1] <= a[i+1]))
{
ans += i - p + 1;
_for(j, p, i - 1)
if(a[j] == a[j+1])
ans--;
x = a[i];
p = i + 1;
}
else { ans = -1; break; }
}
printf("%d\n", ans);
}
return 0;
}
D. Divide and Summarize
又刚一道,发现只是简单搜索而已
可以发现原来的顺序是没有关系的,所以一开始可以排个序
然后搜索就完事了
用到了unordered_map 如果只需要查找就可以用这个,比map要快。内部是哈希表,每次O(1)
然后搜索中间我还用了个二分和前缀和
然而我发现并没有优化多少,和直接遍历一遍效果差不多。算一下直接遍历就是nlogn,其实已经可以了
还要注意最大值最小值相同的情况,要额外处理一下,不然会一直递归。注意递归出口,写递归先考虑出口
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 10;
unordered_map<int, bool> vis;
int a[MAXN], n, q;
ll s[MAXN];
void dfs(int l, int r)
{
ll sum = s[r] - s[l-1];
if(sum <= 1e9) vis[sum] = 1;
if(l == r) return;
int mid = upper_bound(a + l, a + r + 1, (a[l] + a[r]) >> 1) - a - 1;
if(mid == r) return;
dfs(l, mid); dfs(mid + 1, r);
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &q);
_for(i, 1, n) scanf("%d", &a[i]);
sort(a + 1, a + n + 1);
_for(i, 1, n) s[i] = s[i-1] + a[i];
vis.clear();
dfs(1, n);
while(q--)
{
int x; scanf("%d", &x);
if(vis[x]) puts("Yes");
else puts("No");
}
}
return 0;
}
D. XOR-gun
想了一个半小时,没想出来。
但思考的过程中收获还是很多的
(1)了解了异或的交换律结合律,自反性
利用自反性可以写出类似前缀和的东西
(2)简化思维
我有时候会把问题想复杂
比如这道题,要不符合其实就是存在一个a > b
那就找这个就行了
看了题解感觉太骚了
从每个数的最高位考虑,思考符合条件的特殊情况
如果不符合,发现这个时候n就会变得很小,60左右,
那这时就不用考虑复杂度什么的了
这个思路完全想不到,还是做题太少
先考虑特殊情况,才考虑除特殊情况外的其他情况
#include<bits/stdc++.h>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int MAXN = 2e5 + 10;
int a[MAXN], b[MAXN], s[MAXN], n;
int f(int n)
{
int res = 0;
while(n)
{
res++;
n >>= 1;
}
return res;
}
int get(int l, int r)
{
return s[r] ^ s[l-1];
}
int main()
{
scanf("%d", &n);
_for(i, 1, n)
{
scanf("%d", &a[i]);
b[i] = f(a[i]);
s[i] = s[i-1] ^ a[i];
}
_for(i, 2, n - 1)
if(b[i-1] == b[i] && b[i] == b[i+1])
{
puts("1");
return 0;
}
int ans = 1e9;
_for(l, 1, n - 1)
_for(r, l + 1, n)
_for(m, l, r - 1)
if(get(l, m) > get(m + 1, r))
ans = min(ans, r - l - 1);
printf("%d\n", ans == 1e9 ? -1 : ans);
return 0;
}
周五休息,周六日打校赛了