弹珠堆放

递推式,非常小,直接模拟
答案等于
划分

- 因为总和为,因此可以dp,就是一个存在性01背包问题
- 答案为
偶串

- 直接一个桶记录就好
- 才发现,蓝桥杯oj使用
exit(0)会段错误得使用sys.exit(0)
py
import sys
from collections import defaultdict
input=lambda:sys.stdin.readline().strip()
read=lambda:map(int,input().split())
d=defaultdict(int)
s=input()
for c in s:
d[c]+=1
for x,y in d.items():
if y%2==1:
print('NO')
sys.exit(0)
print('YES')交易账本
恶心的模拟题
py
import sys
from collections import defaultdict
input=lambda:sys.stdin.readline().strip()
read=lambda:map(int,input().split())
def solve():
n,m=read()
acc=[[] for _ in range(m)]
vis=[[] for _ in range(m)]
ok=True
for _ in range(m):
s=list(read())
idx=0
x=s[idx]
idx+=1
all=0
f=False
while x:
x-=1
id,c=s[idx],s[idx+1]
idx+=2
if id==-1 and c==-1:
f=True
continue
if c>=len(acc[id]):
ok=False
continue
if vis[id][c]:
ok=False
continue
vis[id][c]=True
all+=acc[id][c]
x=s[idx]
idx+=1
while x:
x-=1
id,c=s[idx],s[idx+1]
idx+=2
all-=c
acc[_].append(c)
vis[_].append(False)
if not f and all!=0:
ok=False
print('YES' if ok else 'NO')
T=1
T=int(input())
for _ in range(T):solve()背包问题


- 看数据应该是枚举其中一种cnt,vp过了赛后交一发t了,神奇的oj
- 首先枚举前面两个桶装A的数量,然后前两个桶贪心地装B
- 那么剩下一个桶呢?肯定是先贪心放体积更小的
- 复杂度
py
import sys
from collections import defaultdict
input=lambda:sys.stdin.readline().strip()
read=lambda:map(int,input().split())
def solve():
B=list(read())
cnta,cntb=read()
va,vb=read()
ans=0
for i in range(min(cnta,B[0]//va)+1):
for j in range(min(cnta-i,B[1]//va)+1):
ra=cnta-i-j
A=[B[0]-i*va,B[1]-j*va,B[2]]
res=i+j
t=min(A[0]//vb+A[1]//vb,cntb)
rb=cntb-t
res+=t
if va<vb:
tmp=min(A[2]//va,ra)
A[2]-=tmp*va
res+=tmp+min(A[2]//vb,rb)
else:
tmp=min(A[2]//vb,rb)
A[2]-=tmp*vb
res+=tmp+min(A[2]//va,ra)
ans=max(ans,res)
print(ans)
T=1+0
T=int(input())
for _ in range(T):solve()翻转


- 很典的线性dp,表示当前是否翻转即可
- 复杂度
py
import sys
from collections import defaultdict
from math import inf
input=lambda:sys.stdin.readline().strip()
read=lambda:map(int,input().split())
def solve():
n=int(input())
dp=[[inf]*2 for _ in range(n+1)]
s=[0]*(n+1)
for i in range(1,n+1):
s[i]=input()
dp[1][0]=dp[1][1]=2
for i in range(2,n+1):
for x in range(2):
for y in range(2):
dp[i][y]=min(dp[i][y],dp[i-1][x]+2-(s[i][y]==s[i-1][x^1]))
print(min(dp[n][0],dp[n][1]))
T=1
# T=int(input())
for _ in range(T):solve()最大阶梯


- 全场第二恶心的题
- vp没想好居然旋转了45度再dp
- 实际上直接dp四次就行
- 复杂度
py
import sys
from collections import defaultdict
from math import inf
input=lambda:sys.stdin.readline().strip()
read=lambda:map(int,input().split())
def solve():
n=int(input())
a=[[inf]*(n+2)]
for _ in range(n):a.append([inf]+list(read())+[inf])
a.append([inf]*(n+2))
ans=0
dp=[[0]*(n+10) for _ in range(n+10)]
for i in range(1,n+1):
for j in range(1,n+1):
if a[i][j]==a[i-1][j]==a[i][j-1]:dp[i][j]=min(dp[i-1][j],dp[i][j-1])+1
else:dp[i][j]=1
ans=max(ans,dp[i][j])
dp=[[0]*(n+10) for _ in range(n+10)]
for i in range(n,0,-1):
for j in range(1,n+1):
if a[i][j]==a[i+1][j]==a[i][j-1]:dp[i][j]=min(dp[i+1][j],dp[i][j-1])+1
else:dp[i][j]=1
ans=max(ans,dp[i][j])
dp=[[0]*(n+10) for _ in range(n+10)]
for i in range(1,n+1):
for j in range(n,0,-1):
if a[i][j]==a[i-1][j]==a[i][j+1]:dp[i][j]=min(dp[i-1][j],dp[i][j+1])+1
else:dp[i][j]=1
ans=max(ans,dp[i][j])
dp=[[0]*(n+10) for _ in range(n+10)]
for i in range(n,0,-1):
for j in range(n,0,-1):
if a[i][j]==a[i+1][j]==a[i][j+1]:dp[i][j]=min(dp[i+1][j],dp[i][j+1])+1
else:dp[i][j]=1
ans=max(ans,dp[i][j])
print(ans)
T=1
# T=int(input())
for _ in range(T):solve()最长回文前后缀

- 也是很典的manacher问题
- 注意:前缀和后缀其中一个可以为0(这点题没表述清wa了一个点),其次数据太水,为什么只是t一个点
- 首先最小答案为1
- 如果原本就是回文串,那么输出
- 如果前后缀都选的话,那么假设前缀为,后缀为,且,那么,因此最后的拼接字符串必定是这种形式
- 用manacher预处理出表示以为左端点的最长回文串,表示以为右端点的最长回文串
- 那么我们枚举前后缀的合法长度,假设,然后我们看中间部分是属于前缀还是后缀即可
- 复杂度
py
import sys
from collections import defaultdict
from math import inf
input=lambda:sys.stdin.readline().strip()
read=lambda:map(int,input().split())
def manacher(s):
n=len(s)
s='^#'+'#'.join(s)+'#$'
id,mr=0,0
p=[0]*(len(s))
for i in range(1,2*n+1):
if i<mr:p[i]=min(p[2*id-i],mr-i)
else:p[i]=1
while s[i+p[i]]==s[i-p[i]]:p[i]+=1
if i+p[i]>mr:
id=i
mr=i+p[i]
return p
def solve():
s=input()
p=manacher(s)
# print(p)
n=len(s)
L=[0]*(n+1)
R=[0]*(n+1)
for i in range(1,2*n+1):
if p[i]<=1:continue
r=(p[i]-1)//2
if i%2==0:
L[i//2-r]=max(L[i//2-r],p[i]-1)
R[i//2+r]=max(R[i//2+r],p[i]-1)
else:
L[i//2-r+1]=max(L[i//2-r+1],p[i]-1)
R[i//2+r]=max(R[i//2+r],p[i]-1)
Len=0
i,j=0,n-1
ok=0
while i<=j:
if s[i]!=s[j]:
Len=i
ok=1
break
i+=1
j-=1
if not ok:
print(2*n)
return
if Len==0:
print(1)
return
# for i in range(1,n):print(i,L[i],R[i])
ans=0
for l in range(1,Len+1):
# print(l,2*l+L[l+1],2*l+R[n-l])
ans=max(ans,l*2+L[l+1],l*2+R[n-l])
print(ans)
T=1
# T=int(input())
for _ in range(T):solve()贸易航线


- 思维题
- 关键点:每次卖出肯定是只卖一种商品更优的
- 因此我们每次看卖哪种商品即可
- 定义为在第个点,刚好卖出所有物品的最大收益
- 定义表示前面买入了物品后的最大收益
- 那么转移很简单,如果不卖任何商品
- 卖第个物品,
- 更新,
py
import sys
from collections import defaultdict
from math import inf
input=lambda:sys.stdin.readline().strip()
read=lambda:map(int,input().split())
def solve():
n,m,k=read()
P=[[0]*(n+1)]
dp=[-inf]*(n+1)
dp[0]=0
for i in range(n):
P.append([0]+list(read()))
mx=[-inf]*(m+1)
ans=0
for i in range(1,n+1):
dp[i]=max(dp[i],dp[i-1])
for j in range(1,m+1):
if P[i][j]==-1:continue
dp[i]=max(dp[i],mx[j]+P[i][j]*k)
for j in range(1,m+1):
if P[i][j]==-1:continue
mx[j]=max(mx[j],dp[i]-P[i][j]*k)
ans=max(ans,dp[i])
print(ans)
T=1
# T=int(input())
for _ in range(T):solve()困局


- 暴力,可以拿30%
- 打表发现k为奇数无解
py
import sys
from collections import defaultdict
from math import inf
input=lambda:sys.stdin.readline().strip()
read=lambda:map(int,input().split())
MOD=998244353
n,k=read()
if k%2==1:
print(0)
sys.exit(0)
match=[0]*(n+1)
def check():
x=0
cnt=0
vis=[0]*(n+1)
while True:
x+=1
if x>n:break
if match[x] and not vis[x]:
vis[x]=1
x=match[x]
cnt+=1
return cnt==2*k
ans=[0]
def dfs(x,st):
if x==k+1:
if check():
ans[0]+=1
# print(match[1:])
return
for i in range(st+1,n+1):
if match[i]:continue
for j in range(i+1,n+1):
if match[j]:continue
match[i]=j
match[j]=i
dfs(x+1,i)
match[i]=0
match[j]=0
dfs(1,0)
print(ans[0]%MOD)- 发现方案只与这个位置有关,因此我们先令计算出相对顺序的方案数
- vp的时候居然没想到如此简单的方法,但是官方正解好像不是这个。。
- 那么计算出相对顺序后,只需要在n个点选2k个即可,答案就是
py
import sys
from collections import defaultdict
from math import inf
input=lambda:sys.stdin.readline().strip()
read=lambda:map(int,input().split())
MOD=998244353
n,k=0,0
match=[]
def check():
x=0
cnt=0
vis=[0]*(n+1)
while True:
x+=1
if x>n:break
if match[x] and not vis[x]:
vis[x]=1
x=match[x]
cnt+=1
return cnt==2*k
ans=[0]
def dfs(x,st):
if x==k+1:
if check():
ans[0]+=1
# print(match[1:])
return
for i in range(st+1,n+1):
if match[i]:continue
for j in range(i+1,n+1):
if match[j]:continue
match[i]=j
match[j]=i
dfs(x+1,i)
match[i]=0
match[j]=0
nn,kk=read()
if kk%2:
print(0)
sys.exit(0)
k=kk
n=2*k
match=[0]*(n+1)
dfs(1,0)
n=nn
fac=[1]*(n+1)
inv=[0]*(n+1)
for i in range(2,n+1):
fac[i]=fac[i-1]*i%MOD
inv[n]=pow(fac[n],MOD-2,MOD)
for i in range(n-1,-1,-1):
inv[i]=inv[i+1]*(i+1)%MOD
def C(n,m):
if n<m:return 0
return fac[n]*inv[m]*inv[n-m]%MOD
print(ans[0]*C(n,2*k)%MOD)