CF1427
CF1427A
CF1427A题意
给出一个数组 a a a,要求你改变它的元素顺序,使得任意一个前缀和不为 0 0 0,无解输出 N O NO NO,有解给出顺序
CF1427A题解
算下总和 s u m sum sum
- s u m = 0 sum=0 sum=0: 无解
- s u m < 0 sum<0 sum<0:让负数在前面,正数在后面,一定使得前缀和小于 0 0 0
- s u m > 0 sum>0 sum>0:让正数在前面,负数在后面,一定使得前缀和大于 0 0 0
CF1427A代码
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x= 0,f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 51;
int T;vector<int> vec;
signed main(){
T = read();
while(T--){
int n = read();vec.clear();int sum = 0;
for(int i = 1;i <= n;i++){vec.push_back(read());}
for(int i : vec){sum += i;}
if(sum == 0){puts("NO");continue;}
if(sum > 0)sort(vec.begin(),vec.end(),greater<int>());
else sort(vec.begin(),vec.end(),less<int>());
puts("YES");for(int i : vec){printf("%d ",i);}puts("");
}
return 0;
}
CF1427B
CF1427B题意
有一个字符串,对于每一位字符 s i s_i si
- s i = L s_i=L si=L:贡献是零
-
s
i
=
W
s_i=W
si=W:
- s i − 1 = L s_{i-1}=L si−1=L:贡献是一
- s i − 1 = W s_{i-1}=W si−1=W:贡献是二
现在你有 k k k 次修改机会,问最大贡献是多少。
CF1427B题解
一个显而易见的结论是,最优方式一定是将
L
→
W
L\to W
L→W。
然后考虑怎么改。
设一共有
c
n
t
cnt
cnt 个
W
W
W,连续的
W
W
W 段有
x
x
x 个,那么答案就是
(
c
n
t
+
k
)
×
2
−
x
(cnt + k)\times2-x
(cnt+k)×2−x。
现在想让
x
x
x 尽可能小。
贪心的想,尽可能的将两个相距“近”的连续段连在一起,这样就能使得答案尽可能大。
然后就没了。
CF1427B代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int n, k;
vector<int> vec;
char ch[maxn];bool book[maxn];
signed main(){
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);scanf("%s",ch + 1);
bool pre = false;int cnt = 0,len = 0;vec.clear();
for(int i = 1;i <= n;i++){
if(ch[i] == 'W'){pre = true;cnt++;}
if(ch[i] == 'L' && pre){len++;}
else{
if(len)vec.push_back(len),len = 0;
}
}
if(cnt + k >= n){printf("%d\n",n * 2 - 1);continue;}
sort(vec.begin(),vec.end());
int tmp = 0, x = 0;
for(int i = 0;i < vec.size();i++){
tmp += vec[i];
if(tmp > k){
x = vec.size() - i + 1;
break;
}
}
if(k >= tmp && (k || cnt)){x = 1;}
printf("%d\n",(cnt + k) * 2 - x);
}
return 0;
}
CF1427C
CF1427C题意
有一个
r
×
r
(
r
≤
500
)
r\times r(r\le 500)
r×r(r≤500) 的矩阵,其中有
n
(
n
≤
1
0
5
)
n(n\le10^5)
n(n≤105) 个事件,坐标是
(
x
i
,
y
i
)
(x_i,y_i)
(xi,yi),发生时间是
t
i
t_i
ti,所有事件只能在发生瞬间看到。
你初始在
(
1
,
1
)
(1,1)
(1,1),问最多能看到多少个事件?
CF1427C题解
先考虑一个朴素DP
d
p
i
=
max
(
d
p
j
+
(
∣
x
i
−
x
j
∣
+
∣
y
i
−
y
j
∣
≤
t
i
−
t
j
)
)
dp_i=\max(dp_j+(|x_i-x_j|+|y_i-y_j|\le t_i-t_j))
dpi=max(dpj+(∣xi−xj∣+∣yi−yj∣≤ti−tj))
不难发现这个是
O
(
n
2
)
O(n^2)
O(n2) 的,直接T飞了
发现这个
r
r
r 很小,并且第
i
i
i个点,所有的
t
j
≤
t
i
−
2
∗
r
t_j\le t_i-2*r
tj≤ti−2∗r 都一定能从
j
j
j 赶到
i
i
i。
然后就没了。
CF1427C代码
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x= 0,f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 1e5 + 10,maxr = 510;
int n, r;
int x[maxn], y[maxn], t[maxn];
int f[maxn];
signed main(){
r = read(); n = read();x[0] = y[0] = 1;t[0] = 0;
memset(f,-0x3f,sizeof(f));f[0] = 0;
for(int i = 1;i <= n;i++){t[i] = read(); x[i] = read(); y[i] = read();}
int mx = -0x3f3f3f3f;
for(int i = 1;i <= n;i++){
f[i] = max(mx + 1,f[i]);
for(int j = max(0,i - 2 * r);j < i;j++)
if(abs(x[i] - x[j]) + abs(y[i] - y[j]) <= t[i] - t[j])
f[i] = max(f[i],f[j] + 1);
if(i >= r * 2) mx = max(mx,f[i - r * 2]);
}
int ans = 0;
for(int i = 1;i <= n;i++)ans = max(ans,f[i]);
printf("%d\n",ans);
return 0;
}
CF1427F
CF1427F题意
6 n 6n 6n 张牌,顺序排列,两人轮流操作,每次操作可以选择连续的三张牌放入自己的口袋中,给出第一个人最后得到的牌,构造合法的操作顺序,使得第一个人最后得到的牌为输入给定的牌。
CF1427F题解
这套题怎么这么多构造题?!
首先先考虑一个问题,就是如果没有交替操作的限制怎么做。
简单啊,维护一个
s
t
a
c
k
stack
stack,每次将第
i
i
i 张牌压入栈中,如果连续三个就
p
o
p
pop
pop。
但是现在加上这个限制咋整?
不难发现,如果将上面的
p
o
p
pop
pop 加一些改变,在
p
o
p
pop
pop 的同时分别以“(”,“)”标记下左右端点,这个序列就变成了括号序列,其中想要删除某个括号序列,就必须删除它里面的所有序列。
具体的说,如果有一个
p
o
p
pop
pop,那就让这个被
p
o
p
pop
pop 的“块”向现在的栈顶连有向边。
如果按照这个关系连边…
?
这玩应不是一堆树(森林)吗?(反正是
D
A
G
DAG
DAG)
然后快乐的发现这玩应可以
d
e
q
u
e
deque
deque,具体的说,每次弹出入度为零的点,然后如果更新新的点可以入队,就按照颜色分别向左右端压入。
然后就完了~~~~~~~吗?
Wrong answer on test 2
The sequence of moves produces a different set of cards in Federico’s pocket.
然后你手玩了下 test 2 的输出。
woc第二个人拿的你拿什么?!(怒
突然想到一个问题,如果现在所有颜色是零的点入度都不是零咋整?
突然发现这种问题是由于自己取的方式不对。
比如说这个情况
1
←
0
,
0
1\gets 0,0
1←0,0 现在要取颜色是零的点。
然后你的程序快乐的取了左面的零,然后到颜色是一的时候傻了。
- “这也没有颜色是一,入度是零的点啊?”
- “算了反正取一个就好了我又不是做题的那个,我只是个程序。”
你TM演我?!
于是让程序聪明点,每次让程序尽可能取可以减少入度的点,实在不行在取不能减少入度的点。
这下就真没啦。
CF1427F代码
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 1300;
struct block{
vector<int> vec;
int id, col;
block(int col = 0,int id = 0):col(col),id(id){}
void ins(int x){this->vec.push_back(x);}
}b[maxn];
int tot, n, fa[maxn];
int ind[maxn];
stack<block> stk;
bool book[maxn];
stack<int> que,que1,que2;
signed main(){
n = read() * 3;
for(int i = 1;i <= n;i++){book[read()] = 1;}n *= 2;
for(int i = 1;i <= n;i++){
if(stk.empty() || stk.top().col != book[i]){
stk.push(block(book[i],++tot));
stk.top().ins(i);b[tot] = stk.top();
}
else{
stk.top().ins(i);b[stk.top().id].ins(i);
if(stk.top().vec.size() >= 3){
block tmp = stk.top();stk.pop();
if(stk.empty())continue;
fa[tmp.id] = stk.top().id;
ind[stk.top().id]++;
}
}
}
for(int i = 1;i <= tot;i++){
if(!ind[b[i].id]){
if(b[i].col == 1){que.push(b[i].id);}
else{
if(!fa[b[i].id])que2.push(b[i].id);
else que1.push(b[i].id);
}
}
}
int now = 1,cnt = 0;n /= 3;
while(cnt < n){
block tmp = block();
if(now){tmp = b[que.top()];que.pop();}
else{
if(!que1.empty()){tmp = b[que1.top()];que1.pop();}
else {tmp = b[que2.top()];que2.pop();}
}
for(int i : tmp.vec){printf("%d ",i);}puts("");
ind[fa[tmp.id]]--;
if(!ind[fa[tmp.id]]){
if(b[fa[tmp.id]].col == 1){que.push(b[fa[tmp.id]].id);}
else{
if(!fa[b[fa[tmp.id]].id]){que2.push(b[fa[tmp.id]].id);}
else que1.push(b[fa[tmp.id]].id);
}
}
now ^= 1;cnt++;
}
return 0;
}