曇天も払う光なら凄惨な旅路だって往ける 若这束光芒能驱散黑暗 拨云见日 哪怕旅途灰|

AzusidNya

园龄:1年7个月粉丝:4关注:4

LGJOI-2023.8.7

sto Bronya19C.

A

题意:

一个长度为 n01 串,其中只有 1 个数为 1 。每次将一个长度为 k 的字串翻转。

对于每个 i 询问 1 最少多少次操作可以将它翻转到 s 。另外有些位置任意时刻不能有 1

对于每个 i ,如果无法做到输出 1

n105

Solution:

一种简单的方法是直接BFS。

考虑 i 能转移到 j 的条件。

  • 2×max(ik+1)+ku1jmin(nk+1,u)

  • ijk (mod2)

考虑优化 BFS 。用 set 维护奇数和偶数未更新点的集合,每次更新完点后删除这些点,即可做到每个仅更新一次。时间复杂度 O(nlogn)

Code:
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<set>
using namespace std;
int flg[100005], n, k, m, s;
int f[100005];
bool inque[100005];
queue<int> q;
set<int> s1, s2;
int main(){
cin >> n >> k >> m >> s;
for(int i = 1; i <= n; i += 2)
s1.insert(i);
for(int i = 2; i <= n; i += 2)
s2.insert(i);
for(int i = 1, v; i <= m; i ++)
cin >> v, flg[v] = true;
if(k == 1 || n < k){
for(int i = 1; i <= n; i ++)
cout << (((i == s && (!flg[i]))) ? 1 : -1) << " ";
return 0;
}
if(flg[s]){
for(int i = 1; i <= n; i ++) cout << "-1 ";
return 0;
}
memset(f, -1, sizeof(f));
if(k == 2){
for(int i = s; i <= n; i ++)
if(flg[i])
break;
else f[i] = i - s;
for(int i = s; i >= 1; i --)
if(flg[i]) break;
else f[i] = s - i;
for(int i = 1; i <= n; i ++)
cout << f[i] << " ";
return 0;
}
f[s] = 0;
q.push(s);
while(!q.empty()){
int u = q.front();
q.pop();
if(((2 * max(u - k + 1, 1) + k - u - 1) % 2) == 1){
auto it = s1.lower_bound(2 * max(u - k + 1, 1) + k - u - 1);
auto it2 = it;
for(; it != s1.end() && *it <= 2 * (min(n - k + 1, u)) + k - u - 1; it ++)
if(f[*it] == -1 && !flg[*it]){
f[*it] = f[u] + 1;
q.push(*it);
}
if(it2 != it)
s1.erase(it2, -- it);
}
else{
auto it = s2.lower_bound(2 * max(u - k + 1, 1) + k - u - 1);
auto it2 = it;
for(; it != s2.end() && *it <= 2 * (min(n - k + 1, u)) + k - u - 1; it ++)
if(f[*it] == -1 && !flg[*it]){
f[*it] = f[u] + 1;
q.push(*it);
}
if(it2 != it)
s2.erase(it2, -- it);
}
}
for(int i = 1; i <= n; i ++)
cout << f[i] << " ";
return 0;
}

B

题意:

给定一个由通配符 ? 和括号组成的序列,求有多少个子串可以通过通配符替换为左右括号而变为括号序列。

Solution:
Subtask 1: 括号串中只有 ?

暴力枚举括号串长度即可。

Subtask 3、4: |S|2000

递推。设 fi,j 表示 [i,j] 是否能变成合法的的括号串。

假设当前状态为 fi,j ,那么它能成为合法的括号串,即取值为 1 需满足以下条件任一:

  • fi+1,j1=1i+1 , j+1 两个位置的字符可以配成一对括号。
  • 存在一个位置 x 满足 fi,x=1fx+1,j=1

按照这两个条件递推即可。

通过一些显而易见的剪枝可以跑过这个 Subtask 。

for(int i = 0; i <= n; i ++)
f[i + 1][i] = 1;
for(int l = 2; l <= n; l += 2)
for(int i = 1; i + l - 1 <= n; i ++){
int j = i + l - 1;
if((a[i] == '(' && a[j] == ')') || (a[i] == '?' && a[j] == ')') || (a[i] == '(' && a[j] == '?') || (a[i] == '?' && a[j] == '?'))
f[i][j] = (f[i][j] || f[i + 1][j - 1]);
for(int k = i + 1; k < j; k += 2)
if(f[i][k] && f[k + 1][j]){
f[i][j] = 1;
break;
}
}
for(int i = 1; i <= n; i ++)
for(int j = i; j <= n; j ++){
ans += f[i][j];
}
cout << ans;
Subtask 2: 括号串中没有 ?

本文作者:AzusidNya の 部屋

本文链接:https://www.cnblogs.com/AzusidNya/p/17611419.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   AzusidNya  阅读(35)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起