初中信息奥赛模拟测试
初中信息奥赛模拟测试
T1 ZEW 玩扫雷
\(n\) 和 \(m\) 都是小的,枚举即可。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N=1010;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=1;
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,sum[N][N];
char a[N][N];
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
read(n),read(m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]=='.')
{
if(i-1>0&&j-1>0&&a[i-1][j-1]=='*') sum[i][j]++;
if(i-1>0&&j>0&&a[i-1][j]=='*') sum[i][j]++;
if(i-1>0&&j+1<=m&&a[i-1][j+1]=='*') sum[i][j]++;
if(i>0&&j-1>0&&a[i][j-1]=='*') sum[i][j]++;
if(i>0&&j+1<=m&&a[i][j+1]=='*') sum[i][j]++;
if(i+1<=n&&j-1>0&&a[i+1][j-1]=='*') sum[i][j]++;
if(i+1<=n&&j+1<=m&&a[i+1][j+1]=='*') sum[i][j]++;
if(i+1<=n&&j>0&&a[i+1][j]=='*') sum[i][j]++;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
if(a[i][j]=='.') cout<<sum[i][j];
else cout<<a[i][j];
cout<<endl;
}
}
- 注意 当 \(a_{i,j}\) 是 \("."\) 时,他周围可能一个地雷也没有,那么此时 \(sum_{i,j}\) 就是 \(0\)。
所以最后输出时,一定不能是
不然所有的 \(0\) 都会输出成 \("."\),像这样:if(sum[i][j]!=0) cout<<sum[i][j];
所以这道题爆零了 \(qwq\)
复杂度 \(O(nm)\)
T2 ZEW 的游戏
显然所有平行的直线中只能要一个。
那么我们可以通过 \(\dfrac{y_i-y_j}{x_i-x_j}\) 求出斜率 \(k\),所以就是求能求出的 \(k\) 的个数。
所以可以先把所有的直线的 \(k\) 都求出来,之后可以排序再去重,也可以用 \(map\)。
建 \(map\) 时 \(<>\) 内第一个是下标( \(key\) ),第二个是返回值( \(value\) )。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N=1010;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=1;
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,ans,tot;
double c[N*N];
struct aa
{
int x,y;
}e[N];
map<double,bool>q;
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
read(n);
for(int i=1;i<=n;i++)
read(e[i].x),read(e[i].y);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
if(e[i].x!=e[j].x) c[++tot]=(double)(e[i].y-e[j].y)/(e[i].x-e[j].x);
else c[++tot]=0x7f7f7f;
if(!q[c[tot]]) ans++;
q[c[tot]]=1;
}
cout<<ans;
}
\(k\) 一定要是 \(double\),所以代码中第 \(35\) 行括号里的 \(double\) 一定要加,\(\times 1.0\) 不好使 \(qwq\)
所以也爆零了
复杂度 \(O(n^2log(n))\)
T3 ZEW 学分块
可以用双指针,定义 \(l,r\)。
枚举第二个分割点 \(r\),由此将 \(r\) 固定住,再去搞前两个分块。
而当前两个块差值最小的时候,也就是他们两个中最大值最小的时候,那么去找到第一个左块大于右块的 \(l\) 和最后一个左块小于右块的 \(l\),选择他们之中最优的那一个,去更新 \(ans\)。
通过赛时打出的暴力,我们知道每种情况的 \(ans\) 呈一个不规则的二次函数形状,所以出现第一个当前 \(ans\) 大于等于已经推出的 \(ans\) 时,就可以 \(break\) 了。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N=5e7+10;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=1;
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,a[N],sum[N],l,r,ans=0x7f7f7f7f;
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
read(n);
for(int i=1;i<=n;i++)
read(a[i]),
sum[i]=sum[i-1]+a[i];
l=1,r=2;
while(r<n)
{
while(sum[l]<sum[r]-sum[l]&&l<r) l++;
if(min({max({sum[l],sum[r]-sum[l],sum[n]-sum[r]}),max({sum[l-1],sum[r]-sum[l-1],sum[n]-sum[r]})})>=ans) break;
ans=min({ans,max({sum[l],sum[r]-sum[l],sum[n]-sum[r]}),max({sum[l-1],sum[r]-sum[l-1],sum[n]-sum[r]})});
r++;
}
cout<<ans;
}
复杂度 \(O(n)\) (光输入已经 \(O(n)\) 了)
- 直接暴力的话超时 \(40\) 分,虽然根据他呈不规则二次函数而加了 \(n\) 个 \(break\) 。( \(n\) 是虚数)
- 至于数据范围中给了一个 \(1\le a_i\le 233\),所以隔壁 @\(minecraft666\) 直接暴力枚举 \(233^2\),然后 \(A\) 掉了,
就很离谱。 - 当然这道题正解应是二分答案,但 \(m=3\),所以双指针也是可以的。
T4 ZEW 玩 thd
不难看出来是道 \(DP\),所以赛时没打出来。
根据贪心思想,让塔尽可能多的打,然后人补刀,是最赚的。
由此先搞出几个变量:
对于第 \(i\) 个小兵
- 设塔的攻击秒数为 \(t_i\),则 \(t_i\) 为满足 \(t_i\times q<h_i\) 的最大正整数值。
- 设人的攻击秒数为 \(r_i\),则 \(r_i=\lceil\dfrac{h_i-q\times t_i}{p}\rceil\)。
然后进行背包 \(DP\)。
-
人和塔的攻击是同步的,在每一秒里,塔都会进行攻击,而人可以选择攻击或不攻击。
-
所以我们设一个 \(DP\) 常用的 \(f_{i,j}\),\(i\) 是攻打第 \(i\) 个小兵,\(j\) 是进行到第 \(j\) 秒。
-
如果这一个小兵不对他补刀,
那么收到的钱就是 \(0\),则需要让塔自己负责把他打死
此时 \(f_{i,j+t_i+1}=max(f_{i,j+t_i+1},f_{i-1,j})\)
\(j+t_i+1\) 是第 \(i-1\) 个小兵死了之后,\(i\) 存活的秒数。
-
如果这个小兵我选择去补刀,
首先需要判断能不能杀死他,即 \(j+t_i-r_i>0\)
本来他能活到 \(j+t_i\) 秒后再死,现在人也去打他,那么他活的就更短了,所以是 \(j+t_i-r_i\)
此时 \(f_{i,j+t_i-r_i}=max(f_{i,j+t_i-r_i},f_{i-1,j}+g_i)\),此时如果杀掉他更赚钱,就得到 \(g_i\) 元
最后输出 \(f_{n,j}\) 最大值即可,即在第几秒把第 \(n\) 个小兵打死。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N=200;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=1;
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);
}
int p,q,n,h[N],g[N],sum,t[N],r[N],f[N][N*N],ans;
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
read(p),read(q),read(n);
for(int i=1;i<=n;i++)
read(h[i]),read(g[i]),
t[i]=(h[i]%q==0)?(h[i]/q-1):(h[i]/q),
r[i]=ceil(1.0*(h[i]-q*t[i])/p),
sum+=t[i]+1;
memset(f,-0x3f,sizeof(f)),f[0][1]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=sum;j++)
{
f[i][j+t[i]+1]=max(f[i][j+t[i]+1],f[i-1][j]);
if(j-(r[i]-t[i])>=0)
f[i][j-(r[i]-t[i])]=max(f[i][j-(r[i]-t[i])],f[i-1][j]+g[i]);
}
for(int i=0;i<=sum;i++) ans=max(ans,f[n][i]);
cout<<ans;
}
而至于代码中的 \(sum\) 就是总共可以用的时间,而这个 \(sum+=t[i]+1\) 如何理解,虽然在这一秒小兵死定了,但和 \(PvZ\) 一样,他死了也要在那儿站一秒,消耗一秒时间去打他,他才死透了。
这个 \(n\) 这么小就不要去考虑复杂度了嘛
论爆零
\(T1,T2\) 全都爆零了,导致这次模拟赛只有 \(70\) 分。考完情绪异常崩溃,恰好赶上放假,直接提前离校了。
而爆零的原因也是那么抽象,只是几个字母的区别就从 \(100\) 直接变成 \(0\),当时非常抱怨这场比赛为什么值提供一个样例,但凡和 \(\text{CSP}\) 一样再给个大样例也不会这样的啊。
而恰恰就是这样的,对于自己平时计算就没怎么算对过,和这次爆零也就差不多。
平时做题一直是很快,不管 \(\text{OI}\) 还是数学作业,但是很少全对,因为计算算不对。\(T1,T2\) 一共用了 \(10\) 分钟,\(T1\) 还没断网就交了,然而是爆零的。
也是心态的问题,太紧张了,把这次考试看的太重要了。
主要还是惧怕中考,看样子还是要中考了,之前再怎么也没用了。
一直以为我们这组是没有理由要别人的,作为一个新生,又有谁能半年就拿 \(\text{CSP}\) 一等,然而不认真的性格导致我大概率与直升无缘了。
所以再怎么想也是没用的了,只能当做一次教训了,以后,认真点,别再爆零了,文化课也是,不要因为低错一扣十几分了。
体育也是改革了,中考还是有希望的……
所以继续加油吧,我和 \(\text{OI}\) 的故事不会到此就结束的。
原来 咽回去的泪
才能 淹没了脆弱
你 发誓更勇敢 一生与梦相拥
还 想要继续吗
要 逆风不退啊
让痛苦住进 你眼眸
别怕 未来的模样
辜负 曾经的凝望
有 多少理想 就有 多少次传唱
那 沿途的风浪
也 不过就这样
这一路光景 有你在身旁
要炙热啊 要不忘啊 要勇往啊
起风了 呼唤了 你还在等什么
挥手了 再见了 别不舍回头啊
向心中的梦啊 去追吧
要能留下伤痕才算活过
愿你记得 愿你哭过 不惧脆弱