初三奥赛模拟测试5
前言
-
\(T1~100pts\) :最开始没想出来,打了 \(T3\) 才去打。
-
\(T2~0pts\) :代码太难调没打出来。
-
\(T3~0pts\) :记忆化打假了,而且 \(ans\) 初始值忘记为 \(0\) ,且捆绑测试……
-
\(T4~0pts\) :无人会。
-
比赛链接 。
T1 特殊字符串
用 \(f_i\) 表示前 \(i\) 个字符中并以第 \(i\) 个字符结尾的最大奇异值。
因为每个 \(p_i\) 长度为 \(2\) ,不妨枚举另一个字符进行转移,有:
其中 \(last_j\) 表示字符 \(j\) 上次出现的位置,\(t\) 表示组成的长度为 \(2\) 的字符串会产生多少贡献,至于每个字符串产生多少贡献可以在输入时直接预处理出来。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1e6+10;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
void wt(int x){if(x>9)wt(x/10);putchar((x%10)+'0');}
void write(int x){if(x<0)putchar('-'),x=~x+1;wt(x);}
int n,m,last[N],ans,f[N];
char s[N],t[N];
map<string,int>a;
signed main()
{
// #ifndef ONLINE_JUDGE
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
// #endif
freopen("shiki.in","r",stdin);
freopen("shiki.out","w",stdout);
read(n);
cin>>s+1;
read(m);
for(int i=1,k;i<=m;i++)
cin>>t[1]>>t[2],
read(k),
a[string(t+1)]+=k;
last[s[1]-'a']=1;
for(int i=2;i<=n;i++)
{
t[2]=s[i];
for(int j=0;j<26;j++)
{
if(!last[j]) continue;
t[1]=j+'a';
f[i]=max(f[i],f[last[j]]+a[string(t+1)]);
}
last[s[i]-'a']=i;
ans=max(f[i],ans);
}
write(ans);
}
T2 宝可梦
保证路径唯一,说明其可以构成一棵树的结构,从一个点出发一定能遍历整个图,所以对其进行预处理。
右面没墙就右转,否则能直行就直行,再不行就就左转。
所以对于任意一个.
,对他预处理即可,其最后会形成一个环,此时结束即可,但是他重复走到自己不一定是真正的环,还需要求方向一致。
至于预处理的初始方向,由于选择的时第一个 .
,所以一定满足其左边和上边一定为 X
,所以此时一定是向下,这也就解释了跑四边取最小值为什么是错的。
由于其为一棵树,查询时直接可以算出路径。
就是代码不太好调。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=5e5+10;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
void wt(int x){if(x>9)wt(x/10);putchar((x%10)+'0');}
void write(int x){if(x<0)putchar('-'),x=~x+1;wt(x);}
int n,m,q,f[N<<1][4][2],sum[4];
char a[N<<1];
int gox[4]={-1,1,0,0},goy[4]={0,0,-1,1};//上下左右,直行。
int r[4]={3,2,0,1},l[4]={2,3,1,0};
int id(int x,int y) {return x*(m+2)+y;}
void work(int x,int y,int p)
{
int d=p,tx=x,ty=y;
f[id(x,y)][d][p]=min(sum[p],f[id(x,y)][d][p]);
int xx=x+gox[d],yy=y+goy[d];
if(a[id(xx,yy)]=='.') x=xx,y=yy,sum[p]++;
else d=l[d];
if(a[id(x+gox[r[d]],y+goy[r[d]])]=='.') d=r[d];
while(x!=tx||y!=ty||d!=p)
{
f[id(x,y)][d][p]=min(sum[p],f[id(x,y)][d][p]);
int xx=x+gox[d],yy=y+goy[d];
if(x==tx&&y==ty&&d==p) break;
if(a[id(xx,yy)]=='.') x=xx,y=yy,sum[p]++;
else for(int i=1;i<=3&&(x!=tx||y!=ty||d!=p);i++)
d=r[d];
if(x==tx&&y==ty&&d==p) break;
if(a[id(x+gox[r[d]],y+goy[r[d]])]=='.') d=r[d];
}
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
freopen("pokemon.in","r",stdin);
freopen("pokemon.out","w",stdout);
read(n),read(m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m+1;j++)
if(j==0||j==m+1)
a[id(i,j)]='X';
else cin>>a[id(i,j)];
for(int i=0;i<=m+1;i++)
a[id(0,i)]=a[id(n+1,i)]='X';
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[id(i,j)]=='.')
{
work(i,j,1);
goto Charlie;
}
Charlie:;
read(q);
while(q--)
{
int x,y,xx,yy;
char op;
read(x),read(y),read(xx),read(yy);
cin>>op;
int d=op=='U'?0:(op=='D'?1:(op=='L'?2:3));
int inf=0x3f3f3f3f,ans=inf,p=1;
for(int i=0;i<4;i++)
if(f[id(x,y)][d][p]>=inf||f[id(xx,yy)][i][p]>=inf) continue;
else if(f[id(x,y)][d][p]<=f[id(xx,yy)][i][p])
ans=min(ans,f[id(xx,yy)][i][p]-f[id(x,y)][d][p]);
else ans=min(ans,sum[p]+(f[id(xx,yy)][i][p]-f[id(x,y)][d][p]));
write(ans),puts("");
}
}
T3 矩阵
前言
首先注意初始值为 \(1\) ,出数据的在每个捆绑里都放了一个 \(1\) ,导致大量人员爆零。
其次,卡时常+暴力 \(dfs\) 可过,剪枝+暴力 \(dfs\) 喜提最优解。
只能说数据比较屎。
部分分
-
\(TLE~60pts\) :直接暴力 \(dfs\) ,若一次 \(dfs\) 的公比为 \(d\) ,那么本次 \(dfs\) 的复杂度最多为 \(4^{log_d(maxx)}\) ,\(maxx\) 为其中最大值,\(log\) 以 \(d\) 为底,需要跑 \(nm\) 遍 \(dfs\) 。
-
卡时常,在时间达到 \(980ms\) 时直接结束运行,这能过属实抽象。
点击查看卡时常函数
inline bool check(){return (1.0*clock())/(1.0*CLOCKS_PER_SEC)<=0.98;}
正解
剪枝。
发现每次 \(dfs\) 的 \(ans\) 最大为 \(log_d(maxx)\) ,所以当当前 \(ans>log_d(maxx)\) 时就不进行此次 \(dfs\) ,于是喜提最优解。
貌似不算真正的正解,但我记忆化打假了,懒得调了。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=100010;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
void wt(int x){if(x>9)wt(x/10);putchar((x%10)+'0');}
void write(int x){if(x<0)putchar('-'),x=~x+1;wt(x);}
int n,m,a[N],ans,used[N][4],maxx;
int h[4]={1,0,-1,0},z[4]={0,1,0,-1};
// inline bool check(){return (1.0*clock())/(1.0*CLOCKS_PER_SEC)<=0.98;}
bool check(int i,int j)
{
if(i<1||i>n) return 0;
if(j<1||j>m) return 0;
return 1;
}
void dfs(int i,int j,int sum,int d)
{
ans=max(ans,sum);
for(int l=0;l<4;l++)
if(check(i+h[l],j+z[l]))
if(a[(i+h[l])*m+j+z[l]]%a[i*m+j]==0&&a[(i+h[l])*m+j+z[l]]/a[i*m+j]==d)
dfs(i+h[l],j+z[l],sum+1,d);
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
read(n),read(m);
ans=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
read(a[i*m+j]),
maxx=max(a[i*m+j],maxx);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<4;k++)
if(check(i+h[k],j+z[k]))
if(a[(i+h[k])*m+j+z[k]]==a[i*m+j])
puts("-1"),
exit(0);
else if(a[(i+h[k])*m+j+z[k]]%a[i*m+j]==0)
{
int d=a[(i+h[k])*m+j+z[k]]/a[i*m+j];
if(log(maxx)/log(d)<=ans) continue;
dfs(i+h[k],j+z[k],2,a[(i+h[k])*m+j+z[k]]/a[i*m+j]);
}
write(ans);
}
T4 乘法
不会。