VP CF1837(Div. 2)
绿题以上就写代码
T1:判断奇偶
T2:找最长连续相等的子串
T3:构造成如果碰到"?"就把这个构造成前一个字符
T4:一眼题就是没咋读懂题面。首先思考无解的情况即为左右括号数不相等,输出-1即可。以及有一个显然的结论染色情况就两种,因为满足两个条件的可以合并,于是前缀和来构造即可。要不就是前缀和恒大于等于/小于等于就只输出1,否则根据前缀和来构造。
code
code
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int t,n,a[N],s[N];
char c[N];
int main(){
cin >> t;
while(t--){
cin >> n;
scanf("%s",c + 1);
for(int i = 1;i <= n;i++){
if(c[i] == '(') a[i] = 1;
else a[i] = -1;
}
for(int i = 1;i <= n;i++) s[i] = a[i] + s[i - 1];
if(s[n] != 0){
cout << -1 << endl;
continue;
}
bool flag1 = false,flag2 = false;
for(int i = 1;i <= n;i++){
flag1 |= (s[i] < 0);
flag2 |= (s[i] > 0);
}
if(!(flag1 & flag2)){
cout << 1 << endl;
for(int i = 1;i <= n;i++) cout << 1 << " ";
cout << endl;
continue;
}
cout << 2 << endl;
for(int i = 1;i <= n;i++){
if(s[i] < 0 || s[i - 1] < 0) cout << 1 << " ";
else cout << 2 << " ";
}
cout << endl;
}
return 0;
}
T5:题意很清晰,就你安排一种方案使得每次进行完合并操作后都要剩下编号最小的那几个。看起来有点想分治的感觉,首先还是考虑无解的情况,显然当一组相邻的两个数在编号同一半区的时候无解。都为-1时有两种,其中一个为-1时有一种。乘法原理即可。假设有x个组中有两个-1,y个组中有一个大于size()/2的数方案即为G[x] * F[y] * solve(T)[新的集合]
code
code
#include <bits/stdc++.h>
using namespace std;
const int N = (1 << 19) + 10;
const int MOD = 998244353;
int F[N],G[N],k;
int solve(vector <int> V){
if(V.size() == 1) return 1;
vector <int> T;
int ret = 1,n = V.size(),t = n / 2;
int c = 0,d = n / 2,e = 0;
for(int i = 0;i <= n - 1;i++) d -= (V[i] > t);
for(int i = 0;i <= n / 2 - 1;i++){
int p = i * 2;
int q = i * 2 + 1;
if(V[p] != -1 && V[q] != -1) if((V[p] <= t) == (V[q] <= t)) return 0;
if(V[p] == -1 && V[q] == -1) ++c;
if(V[p] != -1 && V[p] <= t) T.push_back(V[p]);
else if(V[q] != -1 && V[q] <= t) T.push_back(V[q]);
else T.push_back(-1);
}
return (1ll * G[c] % MOD * F[d] % MOD * solve(T) % MOD) % MOD;
}
int main(){
vector <int> p;
cin >> k;
G[0] = F[0] = 1;
for(int i = 1;i <= 1 << k;i++){
G[i] = (1ll * G[i - 1] % MOD * 2) % MOD;//2的i次方
F[i] = (1ll * F[i - 1] % MOD * i) % MOD;//i的阶乘
}
for(int i = 1;i <= 1 << k;i++){
int x;
cin >> x;
p.push_back(x);
}
cout << solve(p);
return 0;
}
T6:有点水的2400。可能是出题人没卡?显然这题一眼可以二分答案,然后用优先队列求出需要的序列长度即可,check本质上是枚举断点。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e5 + 10;
LL q,a[N],n,k,ans;
bool check(LL mid){
LL need[N];
priority_queue <LL> q;
LL sum = 0;
for(LL i = 1;i <= n;i++){
q.push(a[i]);
sum += a[i];
while(sum > mid){
sum -= q.top();
q.pop();
}
need[i] = q.size();
}
sum = 0;
while(!q.empty()) q.pop();
for(LL i = n;i;i--){
q.push(a[i]);
sum += a[i];
while(sum > mid){
sum -= q.top();
q.pop();
}
if(q.size() + need[i - 1] >= k) return 1;
}
return 0;
}
int main(){
cin >> q;
while(q--){
LL l = 0,r = 0;
cin >> n >> k;
for(LL i = 1;i <= n;i++){
cin >> a[i];
r += a[i];
}
while(l <= r){
LL mid = (l + r) >> 1;
if(check(mid)) r = mid - 1,ans = mid;
else l = mid + 1;
}
cout << ans << endl;
}
return 0;
}

浙公网安备 33010602011771号