初三奥赛模拟测试4
初三奥赛模拟测试4
\(T1\) 最后一课 \(100pts\)
-
正解
- 等价于求 \(\min\limits_{x_{0} \in \mathbf{R}}^{} \{ \sqrt{(x_{0}-x_{1})^{2}+(k-y_{1})^2}+\sqrt{(x_{0}-x_{1})^{2}+(k-y_{2})^2} \}^{2}\) 。
- 考虑数形结合(题目已经提示得很明显了),对 \(k,y_{1},y_{2}\) 同侧/异侧进行分讨,跑一遍 将军饮马问题 即可。
点击查看代码
ll work(ll x1,ll y1,ll x2,ll y2) { return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2); } int main() { ll k,x1,x2,y1,y2; cin>>k>>x1>>y1>>x2>>y2; if(y1>y2) { swap(x1,x2); swap(y1,y2); } if(y1==k&&y2==k) { cout<<work(x1,y1,x2,y2)<<endl; } else { if(k<y1) { cout<<work(x1,y1-2*(y1-k),x2,y2)<<endl; } else { if(y1<k&&k<y2) { cout<<work(x1,y1,x2,y2)<<endl; } else { cout<<work(x1,y1+2*(k-y1),x2,y2)<<endl; } } } return 0; }
\(T2\) 日常 \(60pts\)
-
正解
- 排序后二分模拟即可。
点击查看代码
struct node { ll l,x,y,r; }a[100010]; ll vis[100010]; bool cmp(node a,node b) { return a.r<b.r; } bool check(ll mid,ll w) { return a[mid].l<=w; } int main() { ll n,m,k,minl=0x7f7f7f7f,l,r,mid,ans,w,i; cin>>n>>m>>k; for(i=1;i<=n;i++) { cin>>a[i].l>>a[i].x>>a[i].y>>a[i].r; minl=min(minl,a[i].l); } sort(a+1,a+1+n,cmp); for(i=1;i<=k;i++) { cin>>w; if(w<minl||w>m) { cout<<"Failed"<<endl; } else { l=1; r=n; ans=0; while(l<=r) { mid=(l+r)/2; if(check(mid,w)==true) { l=mid+1; ans=mid; } else { r=mid-1; } } if(w<=a[ans].r) { if(vis[ans]==1) { cout<<"Again"<<endl; } else { vis[ans]=1; if(a[ans].x<=w&&w<=a[ans].y) { cout<<"Perfect"<<endl; } else { cout<<"Normal"<<endl; } } } else { cout<<"Failed"<<endl; } } } return 0; }
\(T3\) 渡尘 \(70pts\)
下发快读来自 dysyn1314 ,貌似因为博客园某些特性,代码挂了,过不了编译。
点击查看下发快读
//用法:把这段代码复制到你的代码前面,然后用cin/cout正常写,就会变成快读、快输了。
/* --------------- fast io --------------- */ // begin
namespace Fread {
const int SIZE = 1 << 21;
char buf[SIZE], *S, *T;
inline char getchar() {
if (S == T) {
T = (S = buf) + fread(buf, 1, SIZE, stdin);
if (S == T) return '\n';
}
return *S++;
}
} // namespace Fread
namespace Fwrite {
const int SIZE = 1 << 21;
char buf[SIZE], *S = buf, *T = buf + SIZE;
inline void flush() {
fwrite(buf, 1, S - buf, stdout);
S = buf;
}
inline void putchar(char c) {
*S++ = c;
if (S == T) flush();
}
struct NTR {
~ NTR() { flush(); }
} ztr;
} // namespace Fwrite
#ifdef ONLINE_JUDGE
#define getchar Fread :: getchar
#define putchar Fwrite :: putchar
#endif
namespace Fastio {
struct Reader {
template<typename T>
Reader& operator >> (T& x) {
char c = getchar();
T f = 1;
while (c < '0' || c > '9') {
if (c == '-') f = -1;
c = getchar();
}
x = 0;
while (c >= '0' && c <= '9') {
x = x * 10 + (c - '0');
c = getchar();
}
x *= f;
return *this;
}
Reader& operator >> (char& c) {
c = getchar();
while (c == ' ' || c == '\n') c = getchar();
return *this;
}
Reader& operator >> (char* str) {
int len = 0;
char c = getchar();
while (c == ' ' || c == '\n') c = getchar();
while (c != ' ' && c != '\n' && c != '\r') { // \r\n in windows
str[len++] = c;
c = getchar();
}
str[len] = '\0';
return *this;
}
Reader(){}
} cin;
const char endl = '\n';
struct Writer {
template<typename T>
Writer& operator << (T x) {
if (x == 0) { putchar('0'); return *this; }
if (x < 0) { putchar('-'); x = -x; }
static int sta[45];
int top = 0;
while (x) { sta[++top] = x % 10; x /= 10; }
while (top) { putchar(sta[top] + '0'); --top; }
return *this;
}
Writer& operator << (char c) {
putchar(c);
return *this;
}
Writer& operator << (char* str) {
int cur = 0;
while (str[cur]) putchar(str[cur++]);
return *this;
}
Writer& operator << (const char* str) {
int cur = 0;
while (str[cur]) putchar(str[cur++]);
return *this;
}
Writer(){}
} cout;
} // namespace Fastio
#define cin Fastio :: cin
#define cout Fastio :: cout
#define endl Fastio :: endl
/* --------------- fast io --------------- */ // end
- 弱化版: 牛客 NC275626 小红的数组
- 部分分
- \(70pts\)
-
考虑把绝对值拆开,有 \(\max\limits_{l \le l_{1} \le r_{1} \le r} \{ |\sum\limits_{i=l_{1}}^{r_{1}}a_{i}| \}=\max\limits_{l \le l_{1} \le r_{1} \le r} \{ \sum\limits_{i=l_{1}}^{r_{1}}a_{i},\sum\limits_{i=l_{1}}^{r_{1}}-a_{i} \}\) 。
-
\(\max\limits_{l \le l_{1} \le r_{1} \le r} \{ \sum\limits_{i=l_{1}}^{r_{1}}a_{i} \}\) 可用线段树维护,记录每个区间的最大前缀和、最大后缀和、最大子段和、区间和,然后合并即可。
-
复杂度为 \(O(n+m \log_{2}{n})\) ,因线段树的巨大常数所以只能得到 \(70pts\) 。
- 单次查询: luogu P1115 最大子段和
- 不带修,区间查询,不记录路径: SP1043 GSS1 - Can you answer these queries I
- 不带修,区间查询,记录路径: UVA1400 "Ray, Pass me the dishes!"
- 单点加,区间查询,不记录路径: SP1716 GSS3 - Can you answer these queries III | luogu P4513 小白逛公园
- 区间异或,区间查询,不记录路径: luogu P7492 [传智杯 #3 决赛] 序列
- 区间加,区间查询,不记录路径: luogu P4118 [Ynoi2018] 末日时在做什么?有没有空?可以来拯救吗? | LibreOJ 6265. 最大连续子段和
点击查看代码
ll a[800010]; struct SegmentTree { ll l,r,maxl[2],maxr[2],sum[2],ans[2]; }tree[800010]; ll lson(ll l) { return l*2; } ll rson(ll l) { return l*2+1; } void pushup(ll rt,ll pd) { tree[rt].sum[pd]=tree[lson(rt)].sum[pd]+tree[rson(rt)].sum[pd]; tree[rt].maxl[pd]=max(tree[lson(rt)].sum[pd]+tree[rson(rt)].maxl[pd],tree[lson(rt)].maxl[pd]); tree[rt].maxr[pd]=max(tree[rson(rt)].sum[pd]+tree[lson(rt)].maxr[pd],tree[rson(rt)].maxr[pd]); tree[rt].ans[pd]=max(max(tree[lson(rt)].ans[pd],tree[rson(rt)].ans[pd]),tree[lson(rt)].maxr[pd]+tree[rson(rt)].maxl[pd]); } void build(ll rt,ll l,ll r,ll pd,ll a[]) { tree[rt].l=l; tree[rt].r=r; if(l==r) { tree[rt].sum[pd]=tree[rt].ans[pd]=tree[rt].maxl[pd]=tree[rt].maxr[pd]=a[l]; return; } ll mid=(l+r)/2; build(lson(rt),l,mid,pd,a); build(rson(rt),mid+1,r,pd,a); pushup(rt,pd); } SegmentTree query(ll rt,ll l,ll r,ll pd) { if(l<=tree[rt].l&&tree[rt].r<=r) { return tree[rt]; } ll mid=(tree[rt].l+tree[rt].r)/2; if(r<=mid) { return query(lson(rt),l,r,pd); } else { if(l>mid) { return query(rson(rt),l,r,pd); } else { SegmentTree p=query(lson(rt),l,r,pd),q=query(rson(rt),l,r,pd),num; num.sum[pd]=p.sum[pd]+q.sum[pd]; num.maxl[pd]=max(p.sum[pd]+q.maxl[pd],p.maxl[pd]); num.maxr[pd]=max(q.sum[pd]+p.maxr[pd],q.maxr[pd]); num.ans[pd]=max(max(p.ans[pd],q.ans[pd]),p.maxr[pd]+q.maxl[pd]); return num; } } } int main() { ll n,m,i,l,r; scanf("%lld%lld",&n,&m); for(i=1;i<=n;i++) { scanf("%lld",&a[i]); } build(1,1,n,0,a); for(i=1;i<=n;i++) { a[i]=-a[i]; } build(1,1,n,1,a); for(i=1;i<=m;i++) { scanf("%lld%lld",&l,&r); printf("%lld\n",max(query(1,l,r,0).ans[0],query(1,l,r,1).ans[1])); } return 0; }
-
- \(70pts\)
- 正解
- 普通 \(ST\) 表
-
考虑把绝对值拆开,有 \(\max\limits_{l \le l_{1} \le r_{1} \le r} \{ |\sum\limits_{i=l_{1}}^{r_{1}}a_{i}| \}=\max\limits_{l \le l_{1} \le r_{1} \le r} \{ \sum\limits_{i=1}^{r_{1}}a_{i}-\sum\limits_{i=1}^{l_{1}-1}a_{i},\sum\limits_{i=1}^{l_{1}-1}a_{i}-\sum\limits_{i=1}^{r_{1}}a_{i} \}=\max\limits_{r_{1}=l-1}^{r} \{ \sum\limits_{i=1}^{r_{1}}a_{i} \}-\min\limits_{l_{1}=l-1}^{r} \{ \sum\limits_{i=1}^{l_{1}}a_{i} \}\) ,使用 \(ST\) 表维护即可。
-
时间复杂度为 \(O(n \log_{2}{n}+m)\) 。
点击查看代码
//快读快写已省略 #define cin Fast_IO::fin #define cout Fast_IO::fout ll a[200010],sum[200010],fmaxx[200010][25],fminn[200010][25]; void init(ll n,ll a[]) { memset(fminn,0x3f,sizeof(fminn)); for(ll i=1;i<=n;i++) { fminn[i][0]=fmaxx[i][0]=a[i]; } for(ll j=1;j<=log2(n);j++) { for(ll i=1;i<=n-(1<<j)+1;i++) { fmaxx[i][j]=max(fmaxx[i][j-1],fmaxx[i+(1<<(j-1))][j-1]); fminn[i][j]=min(fminn[i][j-1],fminn[i+(1<<(j-1))][j-1]); } } } ll query_max(ll l,ll r) { ll t=log2(r-l+1); return max(fmaxx[l][t],fmaxx[r-(1<<t)+1][t]); } ll query_min(ll l,ll r) { ll t=log2(r-l+1); return min(fminn[l][t],fminn[r-(1<<t)+1][t]); } int main() { ll n,m,l,r,i; cin(n,m); for(i=1;i<=n;i++) { cin(a[i]); sum[i+1]=sum[i]+a[i]; } init(n+1,sum); for(i=1;i<=m;i++) { cin(l,r); r++; cout(query_max(l,r)-query_min(l,r),'\n'); } return 0; }
-
- 分块优化 \(ST\) 表
- 详见 luogu P3793 由乃救爷爷 。
- the Method of Four Russians
- 猫树
- 普通 \(ST\) 表
\(T4\) 罪人挽歌 \(0pts\)
-
部分分
-
\(0pts\) :输出
No
。 -
\(20pts\) :生成 \(1 \sim n\) 的全排列挨个判断。
点击查看代码
int a[500010],b[500010],p[500010]; int main() { int n,flag,i; cin>>n; for(i=1;i<=n;i++) { cin>>a[i]>>b[i]; p[i]=i; } do { flag=0; for(i=1;i<=n-1;i++) { if(!(a[p[i]]==a[p[i+1]]||b[p[i]]==b[p[i+1]])) { flag=1; break; } } if(flag==0) { for(i=2;i<=n-1;i++) { if((a[p[i-1]]==a[p[i]]&&a[p[i]]==a[p[i+1]])||(b[p[i-1]]==b[p[i]]&&b[p[i]]==b[p[i+1]])) { flag=1; break; } } if(flag==0) { cout<<"Yes"<<endl; for(i=1;i<=n;i++) { cout<<p[i]<<" "; } break; } } }while(next_permutation(p+1,p+1+n)); if(flag==1) { cout<<"No"<<endl; } return 0; }
-
-
正解
- 一个结论:若 \(a_{i-1}=a_{i}\) ,则有 \(b_{i}=b_{i+1}\) 。
- 考虑建图。
- 从 \(a_{i}\) 向 \(b_{i}\) 连一条有向边,此时从 \(a_{1}\) 开始的欧拉路径即是合法的。接着在满足 \(a_{i}=a_{i+1}\) 或 \(b_{i}=b_{i+1}\) 的情况下,类似蛇形走,求欧拉路径即可,记得判断是否存在欧拉路径(有自环)。
- 从 \(b_{i}\) 向 \(a_{i}\) 连一条有向边,此时从 \(b_{1}\) 开始的欧拉路径即是合法的,接下来同理。
- 两次答案取 \(\min\) 即可。
点击查看代码
int a[500010],b[500010],din[500010],dout[500010],id[500010][3],vis[500010]; vector<pair<int,int> >e1[500010],e2[500010]; vector<int>ans1,ans2; stack<int>s; void dfs(int x,int pd) { if(pd==0) { for(int i=id[x][1];i<e1[x].size();i=max(i+1,id[x][1])) { if(vis[e1[x][i].second]==0) { id[x][1]=i+1; vis[e1[x][i].second]=1; dfs(e1[x][i].first,1); s.push(e1[x][i].second); } } } else { for(int i=id[x][2];i<e2[x].size();i=max(i+1,id[x][2])) { if(vis[e2[x][i].second]==0) { id[x][2]=i+1; vis[e2[x][i].second]=1; dfs(e2[x][i].first,0); s.push(e2[x][i].second); } } } } int main() { int n,s1=0,s2=0,sum=0,i; cin>>n; for(i=1;i<=n;i++) { cin>>a[i]>>b[i]; e1[a[i]].push_back(make_pair(b[i],i)); e2[b[i]].push_back(make_pair(a[i],i)); din[a[i]]++; dout[b[i]]++; } for(i=1;i<=n;i++) { sum+=(din[i]%2==1)+(dout[i]%2==1); } if(sum==0||sum==2) { for(i=1;i<=n;i++) { if(din[i]!=dout[i]) { if(din[i]==dout[i]-1) { s1=i; } if(dout[i]=din[i]-1) { s2=i; } } } if(sum==0) { s1=s2=1; } if(s1!=0&&s2!=0) { dfs(a[1],0); while(s.empty()==0) { ans1.push_back(s.top()); s.pop(); } memset(id,0,sizeof(id)); memset(vis,0,sizeof(vis)); dfs(b[1],1); while(s.empty()==0) { ans2.push_back(s.top()); s.pop(); } cout<<"Yes"<<endl; ans1=min(ans1,ans2); for(i=0;i<ans1.size();i++) { cout<<ans1[i]<<" "; } } else { cout<<"No"<<endl; } } else { cout<<"No"<<endl; } return 0; }
总结
- \(T2\)
- 二分前没排序挂分了。
- 大样例没过也没想到为什么没过,难崩。
- \(T3\)
- 没有考虑到线段树的巨大常数。仅仅依靠
Competitive Programming Helper (cph)
插件是不够的。 - 对绝对值的理解能力不强。
- 没有考虑到线段树的巨大常数。仅仅依靠
后记
- \(T2\)
- 题面上标明了 “更多样例见下发文件” ,但没有下发文件。 @Pursuing_OIer 去找 \(miaomiao\) 要的大样例。
- 没排序二分,但因写法较好,大样例没过,但是 \(AC\) 了。
- \(T3\)
- 题面上标明了 “更多样例见下发文件” ,但没有下发文件。 @Pursuing_OIer 去找 \(miaomiao\) 要的大样例。
- 因学校测评机极慢,赛时出题人下发了快读,但本地用的时候没过编译;赛时 \(1s\) 时限在赛后改成了 \(1.5s\) 时限。
- \(T4\)
- 题面上标明了 “更多样例见下发文件” ,但没有下发文件。 @Pursuing_OIer 去找 \(miaomiao\) 要的大样例。
- 因 \(miaomiao\) 没有搬到
Special Judge
,而又有 “假如你的方案的字典序不是最小,但是符合条件,你可以获得 \(50 \%\) 的分数” 的限制,所以用 \(50 \%\) 的数据只有一组解来代替。 - 因 “本题采用捆绑测试,你在一个子任务得到的分数是这个子任务内所有测试点的最小值” ,所以数据中干脆没有
No
的数据点,导致数据过水,欢迎hack
。
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18117484,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。