初三奥赛模拟测试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 &lt;&lt; 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 &lt;&lt; 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&lt;typename T&gt;
    Reader&amp; operator &gt;&gt; (T&amp; x) {
        char c = getchar();
        T f = 1;
        while (c &lt; '0' || c &gt; '9') {
            if (c == '-') f = -1;
            c = getchar();
        }
        x = 0;
        while (c &gt;= '0' &amp;&amp; c &lt;= '9') {
            x = x * 10 + (c - '0');
            c = getchar();
        }
        x *= f;
        return *this;
    }
    Reader&amp; operator &gt;&gt; (char&amp; c) {
        c = getchar();
        while (c == ' ' || c == '\n') c = getchar();
        return *this;
    }
    Reader&amp; operator &gt;&gt; (char* str) {
        int len = 0;
        char c = getchar();
        while (c == ' ' || c == '\n') c = getchar();
        while (c != ' ' &amp;&amp; c != '\n' &amp;&amp; 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&lt;typename T&gt;
    Writer&amp; operator &lt;&lt; (T x) {
        if (x == 0) { putchar('0'); return *this; }
        if (x &lt; 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&amp; operator &lt;&lt; (char c) {
        putchar(c);
        return *this;
    }
    Writer&amp; operator &lt;&lt; (char* str) {
        int cur = 0;
        while (str[cur]) putchar(str[cur++]);
        return *this;
    }
    Writer&amp; operator &lt;&lt; (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\)

        点击查看代码
        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;
        }
        
  • 正解
    • 普通 \(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\)
    • the Method of Four Russians
    • 猫树

\(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
posted @ 2024-04-06 15:34  hzoi_Shadow  阅读(19)  评论(0编辑  收藏  举报
扩大
缩小