CF Round 1096(Div3) YIN
【尹显齐 物理学院】
征战Div.3,一个半小时AC6。
制裁lxgg
2227A. Koshary
很明显,只有
for _ in range(int(input())):
x,y = map(int,input().split())
print("No" if x*y%2 else "Yes")2227B. Party Monster
根据题目描述,我们可以任意重排所有字符的顺序,只需要判断左括号和右括号的数量是否一样。
for _ in range(int(input())):
n = int(input())
s = input()
a,b = 0,0
for i in range(n):
if s[i] == "(":
a += 1
else:
b += 1
if a == b:
print("YES")
else:
print("NO")2227C. Snowfall
我们要让总乘积能被
接下来考虑只能被
for _ in range(int(input())):
n = int(input())
arr = list(map(int,input().split()))
ans = []
for ai in arr:
if ai%6 == 0:
ans.append(ai)
for ai in arr:
if ai%6 and ai%2 == 0:
ans.append(ai)
for ai in arr:
if ai%2 and ai%3:
ans.append(ai)
for ai in arr:
if ai%6 and ai%3 == 0:
ans.append(ai)
print(*ans)2227D. Palindromex
明白一件事,没有
def mex(l,r,arr,n):
s = set()
for i in range(l,r):
s.add(arr[i])
for i in range(n+1):
if i not in s:
return i
for _ in range(int(input())):
n = int(input())
arr = list(map(int,input().split()))
l,r = -1,-1
ans = 1
for i,ai in enumerate(arr):
if ai == 0:
if l == -1:
l = i
else:
r = i
le,ri = l,r
check = 1
while le <= ri:
le += 1
ri -= 1
if le > ri:
break
if arr[le] != arr[ri]:
check = 0
break
if check:
le,ri = l,r
while 1:
le -= 1
ri += 1
if le < 0 or ri > 2*n-1:
le += 1
ri -= 1
break
if arr[le] != arr[ri]:
le += 1
ri -= 1
break
ans = max(ans,mex(le,ri,arr,n))
le,ri = l,l
while 1:
le -= 1
ri += 1
if le < 0 or ri > 2*n-1:
le += 1
ri -= 1
break
if arr[le] != arr[ri]:
le += 1
ri -= 1
break
ans = max(ans,mex(le,ri,arr,n))
le,ri = r,r
while 1:
le -= 1
ri += 1
if le < 0 or ri > 2*n-1:
le += 1
ri -= 1
break
if arr[le] != arr[ri]:
le += 1
ri -= 1
break
ans = max(ans,mex(le,ri,arr,n))
print(ans)这样的话,代码量未免也太大了吧!
我们可以发现,上述代码并没有良好的运用每个数都只有两个这一性质,而在回文序列中,除了中心对称点以外,每个数也正好出现两次。这是否启发我们:可以直接从每个点出发延展回文序列然后进行判断呢?
下面我们将证明:序列中所有长度大于
反证法:如果它们相交,假设相交的子数组中含有某个元素
所以我们发现:序列中所有长度大于
def mex(l,r,arr,n):
s = set()
for i in range(l,r):
s.add(arr[i])
for i in range(n+1):
if i not in s:
return i
for _ in range(int(input())):
n = int(input())
arr = list(map(int,input().split()))
l,r = -1,-1
ans = 1
# 分一个中心点和两个中心点讨论
for l in range(2*n):
le,ri = l,l
while 1:
le -= 1
ri += 1
if le < 0 or ri > 2*n-1:
le += 1
ri -= 1
break
if arr[le] != arr[ri]:
le += 1
ri -= 1
break
ans = max(ans,mex(le,ri,arr,n))
for l in range(2*n-1):
le,ri = l,l+1
if arr[le] != arr[ri]:
continue
while 1:
le -= 1
ri += 1
if le < 0 or ri > 2*n-1:
le += 1
ri -= 1
break
if arr[le] != arr[ri]:
le += 1
ri -= 1
break
ans = max(ans,mex(le,ri,arr,n))
print(ans)2227E. It All Went Sideways
这一问,我们要让移动的方块数最大,我们可以反向考虑:哪些方块不会移动呢?我们从右向左看,每一列不动的方块数量都肯定要少于等于他,于是我们可以从右向左遍历得出不会移动的方块数。(如图中红线以下的方块所示),接下来考虑移走一个方块,我们发现可能影响的方块只是涂成灰色的这些方块,也自然能发现应该移走同一高度连续灰色方块数最多的一行的最右边一个方块。

for _ in range(int(input())):
n = int(input())
arr = list(map(int,input().split()))
ans = sum(arr)-arr[-1]
cur = arr[-1]
idx = n-1
leng = 0
for i in range(n-2,-1,-1):
if arr[i] < cur:# 单调不增
cur = arr[i]
leng = max(leng,idx-i-1)# 最大连续灰色方块长度
idx = i
ans -= cur# 减去无法移动的方块
leng = max(leng,idx)
print(ans+leng)2227F. It Just Keeps Going Sideways
现在,我们要让所有方块的移动距离最大化。
我们先计算不移走方块时所有方块移动距离。我们可以将所有位置的高度从高到低排序,然后从
接下来我们考虑去掉一个方块时的情况,容易发现,在某一位置去掉一个方块会让总距离增加:在这一位置左边,并且方块数量不小于这一位置方块数量的位置数。这就和求逆序对数差不多了,直接使用树状数组处理。
class Fenwick:
def __init__(self,n):
self.n = n
self.bit = [0]*(n+1)
def update(self,idx,delta):
i = idx + 1
while i <= self.n:
self.bit[i] += delta
i += i & -i
def query(self,idx):
i = idx + 1
s = 0
while i > 0:
s += self.bit[i]
i -= i & -i
return s
for _ in range(int(input())):
n = int(input())
arr = list(map(int,input().split()))
ans = 0
bars = sorted([(arr[i],i) for i in range(n)],reverse=True)
count = 0
j = 0
s = 0
for i in range(n,0,-1):
while j < n and bars[j][0] == i:
count += 1
s += n - bars[j][1]
j += 1
ans += s - count*(count+1)//2
st_arr = sorted(list(map(int,set(map(str,arr)))))
dic = {str(v):i for i,v in enumerate(st_arr)}
m = len(st_arr)
bit = Fenwick(m)
res = 0
for x in arr:
idx = dic[str(x)]
if idx > 0:
less = bit.query(idx-1)
else:
less = 0
res = max(res,bit.query(m-1)-less)
bit.update(idx,1)
print(ans+res)