T1
这道题目仔细观察就会发现:
- 异或
- k=1
这就很好办,考虑 k=1 怎么解 3 1 2 4 5 6 7.......... 即可。
异或,找规律发现有很多数字的异或值为0的。最后的答案是有规律的。
不知道什么问题,场上就70分。
T2
这道题目基本上没啥思路,就是弄了个桶10分。
正解:
由于这个题目的字符集大小只有 \(26\) ,我们显然可以枚举出现次数最多与最少的字符是什么。然后把这两个字符离散出来问题就变成了只有 \(1\) 与 \(-1\) 且强制选取至少一个 \(-1\) 的最大连续子段和问题。
然后关于离散,我们显然可以用 vector
把每中字符的出现位置记录下来。然后用类似归并的方法求解即可。
关于强制选取至少一个 \(-1\) 的最大连续子段和问题,我们可以先把答案预设为 \(-1\) 然后到第一个 \(-1\) 时不减即可解决。
由于每种字符作为最大与最小总共被枚举 \(52\) 次,所有字符的数量和为 \(n\)
所以时间复杂度为 \(O(52n)\)
空间复杂度 \(O(n)\)
Code
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
int n;
vector<int> tong[30];
char s[1000005];
int ans;
int main(){
cin>>n>>s;
for(int i=1;i<=n;++i){
tong[s[i-1]-'a'].push_back(i);
}
for(int i=0;i<26;++i){
if(!tong[i].size()){
continue;
}
for(int j=0;j<26;++j){
if(!tong[j].size() || i==j){
continue;
}
int num1=0;int num2=0;
bool f=0;
int cnt=-1;
while(num1<tong[i].size() || num2<tong[j].size()){
int a1,a2;
if(num1==tong[i].size()){
a1=1e9;
}else{
a1=tong[i][num1];
}
if(num2==tong[j].size()){
a2=1e9;
}else{
a2=tong[j][num2];
}
if(a1<a2){
num1++;
cnt++;
}
if(a1>a2){
if(f==1){
cnt--;
}
num2++;
f=1;
}
if(cnt<0){
f=0;
cnt=-1;
}
ans=max(ans,cnt);
}
}
}
cout<<ans<<'\n';
return 0;
}
T3
这道题目我就是对于 sub1的分就是 st表 维护一下。
对于 sub2 的分数就是纯暴力。
正解:
这道题目乍一看并没有什么思路,然后会很沮丧地发现其实两条边根本就是个乘法,根本贪心不了。
当时对这种玄学的东西一看就是 dp,然后又觉得是个斜率优化,因为有值相乘,但是dp根本设计不出来
真正的正解:
然后原题在 这里 ,但是题解并没有看懂。
单调站维护还可以,但是后面的树状数组维护真的很迷糊。
T4
完全不会。
tj:
原题