2021.10.30考试总结[冲刺NOIP模拟19]
T1 特殊字符串
\(pjDP\)。设\(f_{i,j}\)为考虑到第\(i\)个字符,上一个字符为\(j\)的最大值。直接转移。
\(code:\)
T1
#include<bits/stdc++.h>
using namespace std;
namespace IO{
typedef long long LL;
int read(){
LL 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;
}
void write(LL x,char sp){
char ch[20]; int len=0;
if(x<0) x=-x,putchar('-');
do{ ch[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
}
void ckmin(int& x,int y){ x=x<y?x:y; }
void ckmax(LL& x,LL y){ x=x>y?x:y; }
} using namespace IO;
const int NN=100010;
int n,m;
LL k[26][26],f[NN][26],ans;
char s[NN];
signed main(){
freopen("shiki.in","r",stdin);
freopen("shiki.out","w",stdout);
n=read();
scanf("%s",s+1);
m=read();
for(int i=1;i<=m;i++){
char c,h;
cin>>c>>h;
int tmp=read();
k[c-'a'][h-'a']+=tmp;
}
memset(f,0xc0,sizeof(f));
f[1][s[1]-'a']=0;
for(int i=2;i<=n;i++){
for(int j=0;j<26;j++)
ckmax(f[i][j],f[i-1][j]);
for(int j=0;j<26;j++)
ckmax(f[i][s[i]-'a'],f[i-1][j]+k[j][s[i]-'a']);
}
write(f[n][s[n]-'a'],'\n');
return 0;
}
T2 宝可梦
因为每个点间存在唯一简单路径,所以可达点的路径会形成一棵树,在图中行走会形成树的欧拉序。
于是从根走到根,欧拉序会形成一个环,加上题目限制方向(先右再前再左再后),可以发现环是唯一的。
接下来跑出这个环,\(O(1)\)出解。
\(code:\)
T2
#include<bits/stdc++.h>
using namespace std;
namespace IO{
typedef long long LL;
int read(){
LL 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;
}
void write(int x,char sp){
char ch[20]; int len=0;
if(x<0) x=-x,putchar('-');
do{ ch[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
}
void ckmin(int& x,int y){ x=x<y?x:y; }
void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO;
const int NN=500010;
int n,m,q,sx,sy,ex,ey,dr;
int step,stp[NN*2][5],apr[NN*2];
char dct,ch[NN];
bool mp[NN*2],to[NN*2][4];
int id(int x,int y){ return x*(m+2)+y; }
namespace operate{
void move(int& x,int& y,int d){
if(d==0) --x;
if(d==1) ++y;
if(d==2) ++x;
if(d==3) --y;
}
void go(int& x,int& y,int& d){
to[id(x,y)][d]=0; move(x,y,d);
if(to[id(x,y)][(d+1)%4]) d=(d+1)%4;
else if(to[id(x,y)][d]) d=d;
else if(to[id(x,y)][(d+3)%4]) d=(d+3)%4;
else if(to[id(x,y)][(d+2)%4]) d=(d+2)%4;
stp[id(x,y)][d]=++step;
if(x==ex&&y==ey) return;
if(!apr[id(x,y)]) apr[id(x,y)]=step;
}
void search(){
int x=0,y,dir;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
if(mp[id(i,j)]){
int tmp=to[id(i,j)][0]+to[id(i,j)][1]+to[id(i,j)][2]+to[id(i,j)][3];
if(tmp==1){ x=ex=i; y=ey=j; break; }
}
if(x) break;
}
for(int i=0;i<4;i++) if(to[id(x,y)][i]){ dir=i; break; }
do{ go(x,y,dir); }while(x!=ex||y!=ey);
}
} using namespace operate;
signed main(){
freopen("pokemon.in","r",stdin);
freopen("pokemon.out","w",stdout);
n=read(); m=read();
for(int i=1;i<=n;i++){
scanf("%s",ch+1);
for(int j=1;j<=m;j++)
mp[id(i,j)]=(ch[j]=='.');
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(mp[id(i-1,j)]) to[id(i,j)][0]=1;
if(mp[id(i,j+1)]) to[id(i,j)][1]=1;
if(mp[id(i+1,j)]) to[id(i,j)][2]=1;
if(mp[id(i,j-1)]) to[id(i,j)][3]=1;
}
search();
q=read();
while(q--){
sx=read(); sy=read(); ex=read(); ey=read(); cin>>dct;
if(sx==ex&&sy==ey){ puts("0"); continue; }
dr=(dct=='U'?0:(dct=='R'?1:(dct=='D'?2:3)));
int ans=1e9,st=id(sx,sy),ed=id(ex,ey);
for(int i=0;i<4;i++)
if(stp[st][dr]<stp[ed][i]) ckmin(ans,stp[ed][i]-stp[st][dr]);
if(ans==1e9) ans=step-stp[st][dr]+apr[ed];
write(ans,'\n');
}
return 0;
}
T3 矩阵
等比数列长度在有穷的情况下是\(\log\)的,直接搜就完了。
也可以考虑\(DP\),从权值小的点向权值大的点转移。
\(code:\)
T3
#include<bits/stdc++.h>
using namespace std;
namespace IO{
typedef long long LL;
int read(){
LL 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;
}
void write(int x,char sp){
char ch[20]; int len=0;
if(x<0) x=-x,putchar('-');
do{ ch[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
}
void ckmin(int& x,int y){ x=x<y?x:y; }
void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO;
const int NN=80010;
int n,m,ext,ans,mat[NN],f[NN][5],mul[NN][5];
struct node{
int x,y,v;
bool operator<(const node& a){
return v<a.v;
}
}nod[NN];
int id(int x,int y){ return x*m+y; }
int get(int x,int y,int typ){
if(typ==1) return id(x+1,y);
if(typ==2) return id(x-1,y);
if(typ==3) return id(x,y+1);
if(typ==4) return id(x,y-1);
return -1;
}
signed main(){
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
n=read(); m=read(); ans=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
mat[id(i,j)]=read();
nod[++ext]=(node){i,j,mat[id(i,j)]};
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(i>1) if(mat[id(i-1,j)]==mat[id(i,j)]) puts("-1"),exit(0);
if(j>1) if(mat[id(i,j-1)]==mat[id(i,j)]) puts("-1"),exit(0);
}
memset(f,0xc0,sizeof(f));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(i>1&&mat[id(i,j)]%mat[id(i-1,j)]==0)
f[id(i,j)][1]=2, mul[id(i,j)][1]=mat[id(i,j)]/mat[id(i-1,j)];
if(i<n&&mat[id(i,j)]%mat[id(i+1,j)]==0)
f[id(i,j)][2]=2, mul[id(i,j)][2]=mat[id(i,j)]/mat[id(i+1,j)];
if(j>1&&mat[id(i,j)]%mat[id(i,j-1)]==0)
f[id(i,j)][3]=2, mul[id(i,j)][3]=mat[id(i,j)]/mat[id(i,j-1)];
if(j<m&&mat[id(i,j)]%mat[id(i,j+1)]==0)
f[id(i,j)][4]=2, mul[id(i,j)][4]=mat[id(i,j)]/mat[id(i,j+1)];
// cout<<i<<' '<<j<<": "<<"U:"<<mul[id(i,j)][1]<<' '<<"L:"<<mul[id(i,j)][3]<<' '<<"D:"<<mul[id(i,j)][2]<<' '<<"R:"<<mul[id(i,j)][4]<<endl;
}
sort(nod+1,nod+ext+1);
for(int i=1;i<=ext;i++)
for(int j=1;j<=4;j++){
int x=nod[i].x,y=nod[i].y,pos=id(x,y);
if(!mul[pos][j]) continue;
for(int k=1;k<=4;k++){
if(x==n&&k==1) continue;
if(x==1&&k==2) continue;
if(y==m&&k==3) continue;
if(y==1&&k==4) continue;
int to=get(x,y,k);
if(mul[pos][j]!=mul[to][k]) continue;
ckmax(f[to][k],f[pos][j]+1);
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=4;k++)
ckmax(ans,f[id(i,j)][k]);//,cout<<i<<' '<<j<<' '<<k<<' '<<f[id(i,j)][k]<<endl;
write(ans,'\n');
return 0;
}
T4 乘法
暂留