初三奥赛模拟测试1
初三奥赛模拟测试1
\(T1\) 回文 \(0pts\)
-
正解
- 设 \(f_{x_{1},y_{1},x_{2},y_{2}}\) 表示从 \((1,1)\) 到 \((x_{1},y_{1})\) 结束的回文路径条数,其中 \((x_{1},y_{1})\) 关于最终形成的回文串的回文中心的对称点为 \((x_{2},y_{2})\) 。状态转移方程为 \(f_{x_{1},y_{1},x_{2},y_{2}}= \begin{cases} f_{x_{1}-1,y_{1},x_{2},y_{2}+1}+f_{x_{1}-1,y_{1},x_{2}+1,y_{2}}+f_{x_{1},y_{1}-1,x_{2},y_{2}+1}+f_{x_{1},y_{1}-1,x_{2}+1,y_{2}} & A_{x_{1},y_{1}}=A_{x_{2},y_{2}} \\ 0 & A_{x_{1},y_{1}} \ne A_{x_{2},y_{2}} \end{cases}\)
- 因为合法的路径一定满足 \(x_{1}+y_{1}+x_{2}+y_{2}=n+m+2\) ,故可以省去 \(y_{2}\) 这一维。
- 在对角线(非严格意义)统计答案即可。
点击查看代码
const ll p=993244853;//注意模数不是998244353 int f[510][510][510]; char c[510][510]; int main() { int n,m,i,j,x1,x2,y1,y2,ans=0; cin>>n>>m; for(i=1;i<=n;i++) { for(j=1;j<=m;j++) { cin>>c[i][j]; } } f[1][1][n]=(c[1][1]==c[n][m]); for(x1=1;x1<=n;x1++) { for(y1=1;y1<=m;y1++) { for(x2=min(n,n+m+2-x1-y1),y2=n+m+2-x1-y1-x2;x2>=x1&&y2<=m;x2--,y2++) { if(y2>=1&&c[x1][y1]==c[x2][y2]) { f[x1][y1][x2]=(f[x1][y1][x2]+f[x1-1][y1][x2])%p; f[x1][y1][x2]=(f[x1][y1][x2]+f[x1-1][y1][x2+1])%p; f[x1][y1][x2]=(f[x1][y1][x2]+f[x1][y1-1][x2])%p; f[x1][y1][x2]=(f[x1][y1][x2]+f[x1][y1-1][x2+1])%p; } } } } for(x1=1;x1<=n;x1++) { for(y1=1;y1<=m;y1++) { x2=x1; y2=y1; if(x1+y1+x2+y2==n+m+2) { ans=(ans+f[x1][y1][x2])%p; } x2=x1+1; y2=y1; if(x1+y1+x2+y2==n+m+2) { ans=(ans+f[x1][y1][x2])%p; } x2=x1; y2=y1+1; if(x1+y1+x2+y2==n+m+2) { ans=(ans+f[x1][y1][x2])%p; } } } cout<<ans<<endl; return 0; }
- 设 \(f_{x_{1},y_{1},x_{2},y_{2}}\) 表示从 \((1,1)\) 到 \((x_{1},y_{1})\) 结束的回文路径条数,其中 \((x_{1},y_{1})\) 关于最终形成的回文串的回文中心的对称点为 \((x_{2},y_{2})\) 。状态转移方程为 \(f_{x_{1},y_{1},x_{2},y_{2}}= \begin{cases} f_{x_{1}-1,y_{1},x_{2},y_{2}+1}+f_{x_{1}-1,y_{1},x_{2}+1,y_{2}}+f_{x_{1},y_{1}-1,x_{2},y_{2}+1}+f_{x_{1},y_{1}-1,x_{2}+1,y_{2}} & A_{x_{1},y_{1}}=A_{x_{2},y_{2}} \\ 0 & A_{x_{1},y_{1}} \ne A_{x_{2},y_{2}} \end{cases}\)
\(T2\) 快速排序 \(0pts\)
点击查看 qsort/qsort_example.cpp
struct number
{
bool isnan;
int value;
};
bool operator < (const number& x, const number& y)
{
if(x.isnan || y.isnan)
return false;
return x.value < y.value;
}
number tmp[1 << 20];
void qsort(number* _begin, number* _end)
{
if(_begin + 1 >= _end)
return;
number a = *_begin, *s = _begin, *t = tmp;
for(number* p = _begin + 1; p < _end; p++)
{
if(*p < a)*s = *p, s++;
else *t = *p, t++;
}
*s = a, s++;
for(t--; t >= tmp; t--) *(s + (t - tmp)) = *t;
qsort(_begin, s - 1);
qsort(s, _end);
}
-
部分分
- \(12pts\) :因输入中不包含
nan
,故直接排序即可。
- \(12pts\) :因输入中不包含
-
正解
- 因当
left.isnan=1
时,有(A[i]<left)=0
,故L+1
到R
的数都不会被放到left
前;否则将L+1
到R
中小于left.value
的数从小到大放到left
前面。 multiset
大法好,注意迭代器失效问题。
点击查看代码
int b[600000]; string a[600000]; multiset<int>vis; int main() { int t,n,i,j,k; cin>>t; for(i=1;i<=t;i++) { cin>>n; for(j=1;j<=n;j++) { cin>>a[j]; if(a[j]!="nan") { b[j]=0; for(k=0;k<a[j].size();k++) { b[j]=b[j]*10+a[j][k]-'0'; } vis.insert(b[j]); } } for(j=1;j<=n;j++) { if(a[j]=="nan") { cout<<"nan"<<" "; } else { if(vis.find(b[j])!=vis.end()) { while(*vis.begin()<b[j]) { cout<<*vis.begin()<<" "; vis.erase(vis.begin()); } cout<<b[j]<<" "; vis.erase(vis.find(b[j])); } } } cout<<endl; } return 0; }
- 因当
\(T3\) 混乱邪恶 \(0pts\)
-
部分分
-
\(0pts\) :输出
Chaotic evil
。 -
\(97pts\) : \(O(2^{n})\) 爆搜。
点击查看代码
struct node { ll x,id; }a[2000000]; ll vis[2000000]; bool cmp(node a,node b) { return a.x>b.x; } bool dfs(ll x,ll n,ll num,ll sum) { if(num==sum) { return true; } else { if(x==n+1||num>sum) { return false; } else { if(dfs(x+1,n,num+a[x].x,sum)==true) { vis[a[x].id]=1; return true; } else { return dfs(x+1,n,num,sum); } } } } int main() { ll n,m,sum=0,i; cin>>n>>m; for(i=1;i<=n;i++) { cin>>a[i].x; a[i].id=i; sum+=a[i].x; vis[i]=-1; } sort(a+1,a+1+n,cmp); if(dfs(1,n,0,sum/2)==true) { cout<<"NP-Hard solved"<<endl; for(i=1;i<=n;i++) { cout<<vis[i]<<" "; } } else { cout<<"Chaotic evil"<<endl; } return 0; }
-
-
正解
- 2022年普及组1 T2 攻擂?躺平 的 \(01\) 背包做法时间复杂度为 \(O(n^{2}m)\) ,空间复杂度为 \(O(nm)\) ,且难以记录路径,应用至本题会爆炸。
点击查看官方题解
点击查看代码
struct node { ll x,id; }a[2000000],d[2000000]; ll vis[2000000]; bool cmp1(node a,node b) { return a.x<b.x; } bool cmp2(node a,node b) { return (a.x==b.x)?(a.id>b.id):(a.x>b.x); } int main() { ll n,m,sum=0,i; cin>>n>>m; for(i=1;i<=n;i++) { cin>>a[i].x; a[i].id=i; } if(n%2==1) { n++; a[n].x=0; a[n].id=n; } sort(a+1,a+1+n,cmp1); for(i=1;i<=n;i++) { sum+=((i%2==1)?a[i+1].x-a[i].x:0); d[i].x=((i%2==1)?a[i+1].x-a[i].x:0x7f7f7f7f); d[i].id=i; vis[a[i].id]=((i%2==1)?-1:1); } sort(d+1,d+1+n,cmp2); for(i=n/2+1;i<=n&&sum>=1;i++) { if(sum>=2*d[i].x) { sum-=2*d[i].x; swap(vis[a[d[i].id].id],vis[a[d[i].id+1].id]); } } cout<<"NP-Hard solved"<<endl; n-=(a[1].x==0); for(i=1;i<=n;i++) { cout<<vis[i]<<" "; } return 0; }
\(T4\) 校门外歪脖树上的鸽子 \(0pts\)
-
正解
点击查看官方题解
总结
- \(T1\)
- 模数建议复制题面,注意不要打错。
- \(T2\)
- 要搞清算法的本质。
- 要提高读伪代码能力。
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18064513,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。