初三奥赛模拟测试5

前言

image

  • \(T1~100pts\) :最开始没想出来,打了 \(T3\) 才去打。

  • \(T2~0pts\) :代码太难调没打出来。

  • \(T3~0pts\) :记忆化打假了,而且 \(ans\) 初始值忘记为 \(0\) ,且捆绑测试……

  • \(T4~0pts\) :无人会。

  • 比赛链接

T1 特殊字符串

\(f_i\) 表示前 \(i\) 个字符中并以第 \(i\) 个字符结尾的最大奇异值。

因为每个 \(p_i\) 长度为 \(2\) ,不妨枚举另一个字符进行转移,有:

\[f_i=\max_{j=a}^z\{f_i,f_{last_j}+val_t\} \]

其中 \(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 乘法

不会。

posted @ 2024-05-04 17:21  卡布叻_周深  阅读(23)  评论(0编辑  收藏  举报