初三奥赛模拟测试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; }
-
- \(0pts\) :输出
- 正解
-
对上述的 \(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\)
- 把矩阵压成一维的技巧要熟练应用。
- 善用
map
和vector
。
后记
- 下发了大样例,但没有下发普通样例。
- 所有题目的
Subtask1
都是下发的大样例,但得分为 \(0pts\) 。 - \(T3\) 数据非常地“强”,放过去了不少根号分治阈值取假了等非正解的情况,但正解稍微错一点就放不过去了。
- \(miaomiao\) 直接把 多校冲刺 NOIP2021 (19) —「 特殊字符串·宝可梦·矩阵·乘法」 当成官方题解下发了。
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18169271,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。