8.21
不想补旧账了
Brooklyn Round 2 & NNOI Round 2 + 『MGVOI』Round 1 加强赛 未补
还是先把今天的写好吧 CZOI Round 6
大约迟了 \(1h\) 才开始打,场A : A+C,已补 A,B,C
A
当出现两个排列的时候,把其中一个看成有序的,映射到 \(1,2,3,4,...\) 上,在转换另一个是非常常见的思路
这道题可以转 \(a\) ,然后发现其连续的上升子序列都是合法的,统计一下每个上升子序列的长度即可
CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=1e6+5;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
x=(f ? -x : x);
}
int n;
int a[maxn],b[maxn];
int t[maxn];
int main(){
read(n);
for(int i=1;i<=n;i++) read(a[i]);
int in;
for(int i=1;i<=n;i++) read(in),t[in]=i;
for(int i=1;i<=n;i++) a[i]=t[a[i]];
int cnt=0;
LL ans=0;
for(int i=1;i<=n;i++){
++cnt;
if(a[i]>a[i+1]){
ans+=1ll*cnt*(cnt+1)/2;
cnt=0;
}
}
printf("%lld",ans);
return 0;
}
//^o^
B
我把它看成和了... 比C还高的通过率
每次做游戏的点都可以看做一个起点,它可以向上,下,左,右影响其它点
然后因为求最大每个点最大得分,动态规划一下就好了
\[f1[i][j]=max({f1[i-1][j]+k1,f1[i][j-1]+k2,f1[i][j]})
\]
这是左上点的转移
注意一下不同方位的转移需要不同的遍历顺序
CODE
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int maxn=3e3+5;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
x=(f ? -x : x);
}
int p[maxn][maxn];
LL f1[maxn][maxn],f2[maxn][maxn],f3[maxn][maxn],f4[maxn][maxn];
ULL pw[maxn*maxn];
int n,m,q,k1,k2;
int main(){
read(n),read(m),read(q),read(k1),read(k2);
pw[0]=1;
for(int i=1;i<=n*m;i++) pw[i]=pw[i-1]*131;
int x,y,u;
memset(p,0xc0,sizeof(p));
memset(f1,0xc0,sizeof(f1));
memset(f2,0xc0,sizeof(f2));
memset(f3,0xc0,sizeof(f3));
memset(f4,0xc0,sizeof(f4));
while(q--){
read(x),read(y),read(u);
p[x][y]=max(p[x][y],u);
f1[x][y]=f2[x][y]=f3[x][y]=f4[x][y]=p[x][y];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f1[i][j]=max({f1[i-1][j]+k1,f1[i][j-1]+k2,f1[i][j]});
}
}
for(int i=1;i<=n;i++){
for(int j=m;j>=1;j--){
f2[i][j]=max({f2[i-1][j]+k1,f2[i][j+1]+k2,f2[i][j]});
}
}
for(int i=n;i>=1;i--){
for(int j=1;j<=m;j++){
f3[i][j]=max({f3[i+1][j]+k1,f3[i][j-1]+k2,f3[i][j]});
}
}
for(int i=n;i>=1;i--){
for(int j=m;j>=1;j--){
f4[i][j]=max({f4[i+1][j]+k1,f4[i][j+1]+k2,f4[i][j]});
}
}
ULL sum=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
LL ans=max({f1[i][j],f2[i][j],f3[i][j],f4[i][j]});
sum+=ans*pw[(i-1)*m+j];
}
}
printf("%llu",sum);
return 0;
}
//^o^
C
感觉被我写的很麻烦,应该有更好的做法吧
从 \(\frac{n}{2}\) 的前缀开始,比较前后缀是否满足只有一个不相同
同时我们还需要找到这个不相同的位置,这里用双值哈希+二分做即可(单值没有试过,不过应该可以)
找到这个位置后,我们需要讨论到底是前面的改成后面的,还是后面的改成前面的
因为改完以后还有可能继续扩展,所以分别跑一次 \(KMP\) 求整个字符串的 \(border\) ,找最大值就好了
据说有人用模拟做出来了
CODE
#include<bits/stdc++.h>
#define fst first
#define sec second
#define mkp make_pair
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
typedef pair<LL,LL> pii;
const int maxn=1e6+5;
const int B1=131,mod1=998244353;
const int B2=233,mod2=1e9+7;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
x=(f ? -x : x);
}
char s[maxn];
int n;
pii h[maxn];
LL p1[maxn],p2[maxn];
int pi[maxn];
void hsh(){
p1[0]=p2[0]=1;
for(int i=1;i<=n;i++){
h[i]=mkp((h[i-1].fst*B1+s[i])%mod1,(h[i-1].sec*B2+s[i])%mod2);
p1[i]=p1[i-1]*B1%mod1,p2[i]=p2[i-1]*B2%mod2;
}
}
pii get_hsh(int l,int r){
return mkp((h[r].fst-h[l-1].fst*p1[r-l+1]%mod1+mod1)%mod1,\
(h[r].sec-h[l-1].sec*p2[r-l+1]%mod2+mod2)%mod2);
}
bool cmp(int l1,int r1,int l2,int r2){
return get_hsh(l1,r1)==get_hsh(l2,r2);
}
int check(int p,int si){
int l=0,r=si;
int ans=si;
while(l<=r){
int mid=(l+r)>>1;
if(cmp(1,mid,p,p+mid-1)) l=mid+1;
else ans=mid,r=mid-1;
}
if(cmp(ans+1,si,p+ans,n)){
return ans;
}
return 0;
}
int main(){
scanf("%s",s+1);
n=strlen(s+1);
hsh();
int ans=0,st=0;
for(int i=n/2;i>=1;i--){
if(ans=check(n-i+1,i)){
st=n-i+1;
break;
}
}
char temp=s[ans];
s[ans]=s[st+ans-1];
int mx=0;
for(int i=1,j=0;i<n;i++){
while(j&&s[i+1]!=s[j+1]) j=pi[j];
if(s[i+1]==s[j+1]) ++j;
pi[i]=j-1;
}
//printf("%s\n",s+1);
mx=max(mx,pi[n-1]+1);
s[st+ans-1]=s[ans]=temp;
for(int i=1,j=0;i<n;i++){
while(j&&s[i+1]!=s[j+1]) j=pi[j];
if(s[i+1]==s[j+1]) ++j;
pi[i]=j-1;
}
mx=max(mx,pi[n-1]+1);
//printf("%s\n",s+1);
printf("%d",mx);
return 0;
}
//^o^

浙公网安备 33010602011771号