这个div3真是一言难尽...
A maximize
题目:
思路:
无脑暴力
代码:
#include <iostream>
using namespace std;
int gcd(int a, int b) {
return b? gcd(b, a % b): a;
}
void solve() {
int x;
cin >> x;
int ma = 0;
int ans = 1;
for(int i = 1; i < x; i ++ ) {
if(gcd(x, i) + i > ma) {
ma = gcd(x, i) + i;
ans = i;
}
}
cout << ans << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
B prefiquence
题目:
思路:二分板子题.. 据说可以双指针,抽时间补一下
代码:
#include <iostream>
using namespace std;
const int N = 2e5 + 10;
int n, m;
string a, b;
bool check(int k) {
int i = 1, j = 1;
while(i <= k && j <= m) {
if(a[i - 1] == b[j - 1]) i ++;
j ++;
}
if(i == k + 1) return true;
return false;
}
void solve() {
cin >> n >> m >> a >> b;
int l = 0, r = m;
while(l < r) {
int mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
cout << l << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
C Assembly via Remainders
题目:
思路:构造模拟 xi = ai % ai - 1 并且要满足ai > xi + 1由%运算性质可知, ai = k * ai - 1 + xi 让k从1开始遍历,直到使得ai>xi + 1。
代码:
#include <iostream>
using namespace std;
const int N = 510;
int a[N], ans[N];
int n;
void solve() {
cin >> n;
for(int i = 2; i <= n; i ++ ) cin >> a[i];
ans[1] = a[2] + 1;
for(int i = 2; i <= n; i ++ ) {
int x = ans[i - 1] + a[i];
while(x <= a[i + 1]) {
x += ans[i - 1];
}
ans[i] = x;
}
for(int i = 1; i <= n; i ++ ) cout << ans[i] << " ";
cout << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
D permutation game
题目:
思路:由移动规则可知,最终玩家的路径肯定会形成一个最大结点数为n的自环,遍历每个玩家的自环,找到玩家各自的分数最大值
问题:为什么会爆long long????
代码:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 2e5 + 10;
int n, k, pb, ps;
int p[N], a[N];
bool st[N];
unsigned long long get(int k, int cur) {
memset(st, 0, sizeof st);
unsigned long long score = 0;
unsigned long long scr = 0;
while(!st[cur] && k) {
st[cur] = true;
score = max(score, scr + (unsigned long long)a[cur] * k);
scr += a[cur];
cur = p[cur];
k --;
}
return score;
}
void solve() {
cin >> n >> k >> pb >> ps;
for(int i = 1; i <= n; i ++ ) cin >> p[i];
for(int i = 1; i <= n; i ++ ) cin >> a[i];
unsigned long long scoreB = get(k, pb);
unsigned long long scoreS = get(k, ps);
if(scoreB == scoreS) cout << "Draw" << endl;
else if(scoreB > scoreS) cout << "Bodya" << endl;
else cout << "Sasha" << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
E. Cells Arrangement
问题:
这道模拟..不想评价..
F equal xor segments
问题:思路:这道题挺抽象的..相信很多人都能想到前缀和优化异或,然后就不知道怎么处理了...根据异或性质如果有五段分别为x x x x x由于x ^ x = 0, x ^ 0 = x,因此所有奇数数段都可以继续合并成3段(x ^ x ^ x = x | x | x),同样的,偶数数段可以继续合并成两段,因现在只需要判断是否可以找到合法的两段或者三段。对于分成两段的情况,若可以找到任意的i(l <= i < r)使得sum[l - 1] ^ sum[i] == sum[r] ^ sum[i]即判断sum[l - 1] 是否等于 sum[r]这种情况可以在o(1)的时间复杂度内查询。对于分成三段的情况,存在i, j使得sum[i] ^ sum[l - 1] == sum[j] ^ sum[i] == sum[r] ^ sum[j]化简得sum[l - 1] == sum[j], sum[r] == sum[i]并且i < j 并且j < r。对这里的处理也是一大难题,我赛时也止步于此,答案的二分我是真的没有想到。答案中用map<int, vector<int>>存储了前缀异或可能值的下标,由于存储时是顺序存储的,因此下标满足二分条件,只要二分出答案并且判断二分出的答案下标是否满足条件,即可判断这种情况是否成立
problem:
这两段代码有什么区别????
代码:
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
const int N = 2e5 + 10;
int a[N];
int n, q;
void solve() {
map<int, vector<int>> ma;
ma[0].push_back(0);
cin >> n >> q;
for(int i = 1; i <= n; i ++ ) {
cin >> a[i];
a[i] ^= a[i - 1];
ma[a[i]].push_back(i);
}
while(q -- ) {
int l, r;
cin >> l >> r;
if(a[r] == a[l - 1]) {
cout << "YES" << endl;
continue;
}
auto &A = ma[a[r]];
auto &B = ma[a[l - 1]];
int ll = 0, rr = A.size() - 1;
while(ll < rr) {
int mid = ll + rr >> 1;
if(A[mid] >= l) rr = mid;
else ll = mid + 1;
}
int judge = ll;
ll = 0, rr = B.size() - 1;
while(ll < rr) {
int mid = ll + rr + 1 >> 1;
if(B[mid] < r) ll = mid;
else rr = mid - 1;
}
if(A[judge] < B[ll]) cout << "YES" << endl;
else cout << "NO" << endl;
}
cout << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
G division + lcp(easy version)
问题:
思路:二分 + 字符串处理 字符串处理在check中比赛时忘了kmp怎么写了,写的暴力tle了....
tle代码:
bool check(int a) {
int cnt = 1;
string pre = str.substr(0, a);
int idx = a;
for(; idx < n - a + 1; ) {
if(str.substr(idx, a) == pre) {
cnt ++;
idx = idx + a;
} else idx ++;
}
if(cnt >= l) return true;
return false;
}
kmp ac代码:
#include <iostream>
using namespace std;
const int N = 2e5 + 10;
int n, l, r;
char str[N], p[N];
int ne[N];
bool check(int a) {
int cnt = 0;
for(int i = 1; i <= a; i ++ ) p[i] = str[i];
for(int i = 2, j = 0; i <= a; i ++ ) {
while(j && p[i] != p[j + 1]) j = ne[j];
if(p[i] == p[j + 1]) j ++;
ne[i] = j;
}
for(int i = 1, j = 0; i <= n; i ++ ) {
while(j && str[i] != p[j + 1]) j = ne[j];
if(str[i] == p[j + 1]) j ++;
if(j == a) {
cnt ++;
j = 0;
}
}
return cnt >= l;
}
void solve() {
cin >> n >> l >> r;
for(int i = 1; i <= n; i ++ ) cin >> str[i];
int ll = 0, rr = n / r;
while(ll < rr) {
int mid = ll + rr + 1 >> 1;
if(check(mid)) ll = mid;
else rr = mid - 1;
}
cout << ll << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
同样的,字符串哈希也可以很好的解决这个问题
代码
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int P = 131;
const int N = 2e5 + 10;
int n, ll, rr;
char str[N];
unsigned long long h[N], p[N];
unsigned long long get(int l, int r) {
return h[r] - h[l - 1] * p[r - l + 1];
}
bool check(int mid) {
int i = 1;
int cnt = 0;
while(i <= n - mid + 1) {
unsigned long long judge = get(1, mid);
if(get(i, i + mid - 1) == judge) {
i += mid;
cnt ++;
}
else i ++;
}
return cnt >= ll;
}
void solve() {
cin >> n >> ll >> rr;
p[0] = 1;
for(int i = 1; i <= n; i ++ ) cin >> str[i];
for(int i = 1; i <= n; i ++ ) {
p[i] = p[i - 1] * P;
h[i] = h[i - 1] * P + str[i] - '0';
}
int l = 0, r = n / ll;
while(l < r) {
int mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
cout << l << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
}
这个代码在第82个数据点wa了..这里应该是哈希被卡数据了...
本来以为F要用z函数写,还专门去学了学z函数,发现F题的核心并不是z函数....
z函数写法
#include <iostream>
#include <cstring>
using namespace std;
const int N = 2e5 + 10;
int n, ll, rr;
char str[N];
int z[N];
bool check(int mid, int a) {
int cnt = 0;
for(int i = 1; i <= n; i ++ ) {
if(z[i] >= mid) {
cnt ++;
i += mid - 1;
}
}
return cnt >= a;
}
void solve() {
cin >> n >> ll >> rr;
memset(z, 0, sizeof z);
for(int i = 1; i <= n; i ++ ) cin >> str[i];
int boxl = 0, boxr = 0;
z[1] = n;
for(int i = 2; i <= n; i ++ ) {
if(i > boxr) {//i在zbox外
while(i + z[i] <= n && str[i + z[i]] == str[1 + z[i]]) z[i] ++;//在多测时一定要加i + z[i] <= n的条件,否则会被上一个数据影响
boxl = i, boxr = i + z[i] - 1;
} else if(z[i - boxl + 1] <= boxr - i) z[i] = z[i - boxl + 1];
else {
z[i] = boxr - i;
while(i + z[i] <= n && str[i + z[i]] == str[1 + z[i]]) z[i] ++;
boxl = i, boxr = i + z[i] - 1;
}
}
for(int i = ll; i <= rr; i ++ ) {
int l = 0, r = n / i;
while(l < r) {
int mid = 1 + l + r >> 1;
if(check(mid, i)) l = mid;
else r = mid - 1;
}
cout << r << " ";
}
cout << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
}
F diversion + lcp(hard version)
题目: