初三奥赛模拟测试5

初三奥赛模拟测试5

点击查看快读快写代码
#include <cstdio>

using namespace std;
// orz laofudasuan
// modified

namespace io {
	const int SIZE = (1 << 21) + 1;
	char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
	// getchar
	#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
	// print the remaining part
	inline void flush () {
		fwrite (obuf, 1, oS - obuf, stdout);
		oS = obuf;
	}
	// putchar
	inline void putc (char x) {
		*oS ++ = x;
		if (oS == oT) flush ();
	}
	// input a signed integer
	template <class I>
	inline void gi (I &x) {
		for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
		for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;
	}
	// print a signed integer
	template <class I>
	inline void print (I x) {
		if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;
		while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
		while (qr) putc (qu[qr --]);
	}
	//no need to call flush at the end manually!
	struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io :: gi;
using io :: putc;
using io :: print;

int v;

int main () {
	freopen("input.in", "r", stdin);
	freopen("output.out", "w", stdout);
	gi (v);
	print (v);
	putc ('\n');
}

\(T1\) 特殊字符串 \(0pts\)

  • \(f_{i}\) 表示以 \(i\) 为结尾的子序列的最大奇异值,状态转移方程为 \(f_{i}=\max\limits_{j=a}^{z} \{ f_{pos_{j}}+k_{t=js_{i}} \}\) ,其中 \(pos_{j}\) 表示 \(1 \sim i\)\(j\) 最后的出现位置。

  • 注意可能会出现 \(p_{i}\) 相同,但 \(k_{i}\) 不同的情况。

    点击查看代码
    ll f[100010],pos[30];
    char s[100010];
    string t;
    map<string,ll>g;
    ll val(char x)
    {
        return x-'a'+1;
    }
    int main()
    {
        freopen("shiki.in","r",stdin);
        freopen("shiki.out","w",stdout);
        ll n,m,k,ans=0,i,j;
        char pd;
        cin>>n>>(s+1)>>m;
        for(i=1;i<=m;i++)
        {
            cin>>pd;
            t=' ';
            t+=pd;
            cin>>pd;
            t+=pd;
            cin>>;
            g[t]+=k;
        }
        for(i=1;i<=n;i++)
        {
            for(pd='a';pd<='z';pd++)
            {
                if(pos[val(pd)]!=0)
                {
                    t=' ';
                    t+=pd;
                    t+=s[i];
                    f[i]=max(f[i],f[pos[val(pd)]]+g[t]);
                }
            }
            pos[val(s[i])]=i;
            ans=max(ans,f[i]);
        }
        cout<<ans<<endl;
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    

\(T2\) 宝可梦 \(0pts\)

  • 由于保证任意两点间存在唯一简单路径,故从一个点出发,最后到自己的路径是一个环,而每次询问时的路径都是环上的一段,可以通过预处理距离来实现。

  • 选择起点同样会限制了其出发方向,建议选择第一个或最后一个 . 作为起点。

  • \(DFS\) 过程在本地可能会爆栈,需要 ulimit -s unlimited 。也可换做 \(BFS\)

    点击查看代码
    int dis[500010][5],dx[5]={0,0,-1,0,1},dy[5]={0,1,0,-1,0},dirr[5]={0,4,1,2,3},dirl[5]={0,2,3,4,1},len=0;
    map<int,char>a[500010];
    int val(char x)
    {
    	if(x=='R')
    	{
    		return 1;
    	}
    	if(x=='U')
    	{
    		return 2;
    	}
    	if(x=='L')
    	{
    		return 3;
    	}
    	if(x=='D')
    	{
    		return 4;
    	}
    	return 0;
    }
    void dfs(int x,int y,int dir,int n,int m)
    {
    	if(dis[(x-1)*m+y][dir]==0)
    	{
    		len++;
    		dis[(x-1)*m+y][dir]=len;
    		dir=dirr[dir];
    		for(int i=1;i<=4;i++)
    		{
    			if(1<=x+dx[dir]&&x+dx[dir]<=n&&1<=y+dy[dir]&&y+dy[dir]<=m&&a[x+dx[dir]][y+dy[dir]]=='.')
    			{
    				dfs(x+dx[dir],y+dy[dir],dir,n,m);
    			}
    			dir=dirl[dir];
    		}
    	}
    }
    int main()
    {
    	freopen("pokemon.in","r",stdin);
    	freopen("pokemon.out","w",stdout);
    	int n,m,q,ans,sx=0,sy=0,ex,ey,i,j;
    	char pd;
    	cin>>n>>m;
    	for(i=1;i<=n;i++)
    	{
    		for(j=1;j<=m;j++)
    		{
    			cin>>a[i][j];
    			if(a[i][j]=='.')
    			{
    				sx=i;
    				sy=j;
    			}
    		}
    	}
    	dfs(sx,sy,2,n,m);
    	cin>>q;
    	for(i=1;i<=q;i++)
    	{
    		cin>>sx>>sy>>ex>>ey>>pd;
    		ans=0x7f7f7f7f;
    		if(sx==ex&&sy==ey)
    		{
    			ans=0;
    		}
    		else
    		{
    			sx+=dx[val(pd)];
    			sy+=dy[val(pd)];
    			for(j=1;j<=4;j++)
    			{
    				if(dis[(sx-1)*m+sy][val(pd)]!=0&&dis[(ex-1)*m+ey][j]!=0)
    				{
    					ans=min(ans,dis[(ex-1)*m+ey][j]-dis[(sx-1)*m+sy][val(pd)]+((dis[(ex-1)*m+ey][j]-dis[(sx-1)*m+sy][val(pd)]>=0)?1:len));
    				}
    			}
    		}
    		cout<<ans<<endl;
    	}
    	fclose(stdin);
    	fclose(stdout); 
    	return 0;
    }
    

\(T3\) 矩阵 \(0pts\)

  • 部分分
    • \(0pts\) :输出 -1
    • \(100pts\) :由于 \(a_{i} \le 40000\) ,故 \(DFS\) 递归深度不会很深,故暴力 \(DFS\) 加最优性剪枝即可。
      • 时间复杂度貌似是假的,也有可能是我复杂度分析错了。

        点击查看代码
        ll dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
        map<ll,ll>a[40010];
        void dfs(ll x,ll y,ll n,ll m,ll sum,ll q,ll &ans)
        {
        	ans=max(ans,sum);
        	for(ll i=0;i<=3;i++)
        	{
        		if(1<=x+dx[i]&&x+dx[i]<=n&&1<=y+dy[i]&&y+dy[i]<=m&&a[x+dx[i]][y+dy[i]]==a[x][y]*q)
        		{
        			dfs(x+dx[i],y+dy[i],n,m,sum+1,q,ans);
        		}
        	}
        }
        int main()
        {
        	freopen("matrix.in","r",stdin);
        	freopen("matrix.out","w",stdout);
        	ll n,m,maxx=0,ans=1,flag=0,i,j,k;
        	cin>>n>>m;
        	for(i=1;i<=n;i++)
        	{
        		for(j=1;j<=m;j++)
        		{
        			cin>>a[i][j];
        			maxx=max(maxx,a[i][j]);
        		}
        	}
        	for(i=1;i<=n;i++)
        	{
        		for(j=1;j<=m;j++)
        		{
        			for(k=0;k<=3;k++)
        			{
        				if(1<=i+dx[k]&&i+dx[k]<=m&&1<=j+dy[k]&&j+dy[k]<=m&&a[i][j]==a[i+dx[k]][j+dy[k]])
        				{
        					ans=-1;
        					flag=1;
        					break;
        				}
        			}
        			if(flag==1)
        			{
        				break;
        			}
        		}
        		if(flag==1)
        		{
        			break;
        		}
        	}
        	if(flag==0)
        	{    
        		for(i=1;i<=n;i++)
        		{
        			for(j=1;j<=m;j++)
        			{
        				for(k=0;k<=3;k++)
        				{
        					if(1<=i+dx[k]&&i+dx[k]<=n&&1<=j+dy[k]&&j+dy[k]<=m&&a[i+dx[k]][j+dy[k]]%a[i][j]==0&&a[i][j]*pow(a[i+dx[k]][j+dy[k]]/a[i][j],ans)<=maxx)//后面是最优性剪枝
        					{
        						dfs(i+dx[k],j+dy[k],n,m,2,a[i+dx[k]][j+dy[k]]/a[i][j],ans);
        					}
        				}   
        			}
        		}
        	}   
        	cout<<ans<<endl;
        	fclose(stdin);
        	fclose(stdout);
        	return 0;
        }
        
  • 正解
    • 对上述的 \(DFS\) 过程进行记忆化搜索即可。

      点击查看代码
      ll dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
      map<ll,ll>a[40010],f[40010];
      ll dfs(ll x,ll y,ll n,ll m,ll q)
      {
      	if(f[(x-1)*m+y].find(q)==f[(x-1)*m+y].end())
      	{
      		f[(x-1)*m+y][q]=1;
      		for(ll i=0;i<=3;i++)
      		{
      			ll nx=x+dx[i],ny=y+dy[i];
      			if(1<=nx&&nx<=n&&1<=ny&&ny<=m&&a[nx][ny]==a[x][y]*q)
      			{
      				f[(x-1)*m+y][q]=max(f[(x-1)*m+y][q],dfs(nx,ny,n,m,q)+1);
      			}
      		}
      	}
      	return f[(x-1)*m+y][q];
      }
      int main()
      {
      	freopen("matrix.in","r",stdin);
      	freopen("matrix.out","w",stdout);
      	ll n,m,maxx=0,ans=1,flag=0,i,j,k;
      	cin>>n>>m;
      	for(i=1;i<=n;i++)
      	{
      		for(j=1;j<=m;j++)
      		{
      			cin>>a[i][j];
      			maxx=max(maxx,a[i][j]);
      		}
      	}
      	for(i=1;i<=n;i++)
      	{
      		for(j=1;j<=m;j++)
      		{
      			for(k=0;k<=3;k++)
      			{
      				if(1<=i+dx[k]&&i+dx[k]<=m&&1<=j+dy[k]&&j+dy[k]<=m&&a[i][j]==a[i+dx[k]][j+dy[k]])
      				{
      					ans=-1;
      					flag=1;
      					break;
      				}
      			}
      			if(flag==1)
      			{
      				break;
      			}
      		}
      		if(flag==1)
      		{
      			break;
      		}
      	}
      	if(flag==0)
      	{    
      		for(i=1;i<=n;i++)
      		{
      			for(j=1;j<=m;j++)
      			{
      				for(k=0;k<=3;k++)
      				{
      					if(1<=i+dx[k]&&i+dx[k]<=n&&1<=j+dy[k]&&j+dy[k]<=m&&a[i+dx[k]][j+dy[k]]%a[i][j]==0&&a[i][j]*pow(a[i+dx[k]][j+dy[k]]/a[i][j],ans)<=maxx)
      					{
      						if(f[(i-1)*m+j].find(a[i+dx[k]][j+dy[k]]/a[i][j])!=f[(i-1)*m+j].end())
      						{
      							f[(i-1)*m+j][a[i+dx[k]][j+dy[k]]/a[i][j]]=1;
      						}
      						f[(i-1)*m+j][a[i+dx[k]][j+dy[k]]/a[i][j]]=max(f[(i-1)*m+j][a[i+dx[k]][j+dy[k]]/a[i][j]],dfs(i+dx[k],j+dy[k],n,m,a[i+dx[k]][j+dy[k]]/a[i][j])+1);
      						ans=max(ans,dfs(i+dx[k],j+dy[k],n,m,a[i+dx[k]][j+dy[k]]/a[i][j])+1);
      					}
      				}   
      			}
      		}
      	}   
      	cout<<ans<<endl;
      	fclose(stdin);
      	fclose(stdout);
      	return 0;
      }
      

\(T4\) 乘法 \(0pts\)

总结

  • 要理解题目,学会手造样例。
  • \(T2,T3\)
    • 把矩阵压成一维的技巧要熟练应用。
    • 善用 mapvector

后记

  • 下发了大样例,但没有下发普通样例。
  • 所有题目的 Subtask1 都是下发的大样例,但得分为 \(0pts\)
  • \(T3\) 数据非常地“强”,放过去了不少根号分治阈值取假了等非正解的情况,但正解稍微错一点就放不过去了。
  • \(miaomiao\) 直接把 多校冲刺 NOIP2021 (19) —「 特殊字符串·宝可梦·矩阵·乘法」 当成官方题解下发了。
posted @ 2024-05-01 13:26  hzoi_Shadow  阅读(31)  评论(0编辑  收藏  举报
扩大
缩小