初三奧賽模擬測試5

卡布叻_周深發表於2024-05-04

前言

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 寶可夢

保證路徑唯一,說明其可以構成一棵樹的結構,從一個點出發一定能遍歷整個圖,所以對其進行預處理。

右面沒牆就右轉,否則能直行就直行,再不行就就左轉。

所以對於任意一個.,對他預處理即可,其最後會形成一個環,此時結束即可,但是他重複走到自己不一定是真正的環,還需要求方向一致。

由於其為一棵樹,查詢時直接可以算出路徑。

就是程式碼不太好調。

點選檢視程式碼
#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 乘法

不會。