模拟赛25

模拟赛25

最近怎么狂挂不止。

  1. 博弈

    考虑策略,首先是优先最小的,但是由于有重复的,所以在最小个数为偶数时会败,以此类推,可以想到当有一个数出现次数时奇数先手必胜,否则必败。

    考虑将相同的两两相消,发现 \(u\to v\)\(u\to 根\to v\) 是等价的。

    于是每个点维护一下当前的数,问题变成了求和当前集合相同的集合有几个,因为两两相消,可以异或 hash,也可用一些奇怪 hash。

    但是千万千万不要直接用 \(\sum a^n\),这个东西竟然是可以稳定被卡的!

  2. 跳跃

    发现其一定是在一个最大子段中反复横跳,然后在到下一个。

    数据比较水,错解轻松过(于是加了 hack)。

    hack 思路:

    首先是 \(k\)\(min\) 的乱搞,这个轻松卡,就是 \(1,-100000,-100000,100000,100000\) 之类的用长段的负数让你一直在最前面跳,但其是可以到后面。

    这个在大数据随机下效果一般,不到 \(100\) 组就会出错,钦定第一个是 \(1\) 以后十几组就卡掉了。

    然后是一些假了的贪心,就是每次直接向最后一个可以跳到的地方跳,这个原理就是构造前后和的差距不大,但是从前面跳到后面会有较大代价导致不优,像 \(99999,100000,-100000,-100000,-100000,-99998,100000,100000\)\(k\) 比较小的时候。

    这个在小数据随机下效果一般,\(n,k\le 20\) 时十几组就卡了(值域开大点),但是有人数据点分治但 \(n,k\le 20\)dfs T 了没绷住。

    然后有一些逆天的 \(0\),比如 \(k=0\),有的要写特判。

    还有一些暴力会在恰好整除时错,懒得卡了,暴力一般也过不去。

    给一下数据生成器,多生成几组就有了
    #include<bits/stdc++.h>
    using namespace std;
    using llt=long long;
    using llf=long double;
    using ull=unsigned long long;
    #ifdef LOCAL
        FILE *InFile=freopen("in_out/in.in","r",stdin),*OutFile=freopen("in_out/in.in","w",stdout);
    #else
        FILE *InFile=stdin,*OutFile=stdout;
    #endif
    
    mt19937 rnd(ull(new char)*ull(new char));
    
    int main(){
        ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
        cout<<10<<endl;
        for(int t=1;t<=10;++t){
            int k=rnd()%10+1;
            if(k<=2){
                int n=901+rnd()%100,k=999999901+rnd()%100; cout<<n<<' '<<k<<endl;
                for(int i=1;i<=n;++i){
                    if(rnd()%5==0) cout<<0<<' '; 
                    else cout<<int(rnd()%200000)-100000<<' '; 
                }cout<<endl;
            }else if(k<=4){
                int n=901+rnd()%100,k=999999901+rnd()%100; cout<<n<<' '<<k<<endl;
                cout<<1<<' '; for(int i=2;i<=n;++i) cout<<int(rnd()%200000)-100000<<' '; cout<<endl;
            }else if(k<=6){
                int n=10+rnd()%10,k=10+rnd()%10; cout<<n<<' '<<k<<endl;
                for(int i=1;i<=n;++i) cout<<int(rnd()%200000)-100000<<' '; cout<<endl;
            }else if(k<=8){
                int n=rnd()%1000+1,k=rnd()%1000000000+1; cout<<n<<' '<<k<<endl;
                for(int i=1;i<=n;++i) cout<<int(rnd()%200000)-100000<<' '; cout<<endl;
            }else{
                int n=rnd()%1000+1; cout<<n<<' '<<0<<endl;
                for(int i=1;i<=n;++i) cout<<int(rnd()%200000)-100000<<' '; cout<<endl;
            }
        }
    }
    
  3. 大陆

    水题,建议改名:树分块前置。

    就是考虑维护子树中没有被选的,合并到父亲上,如果 \(\ge B\) 就单开一个,以父节点为省会。

    最后的根直接归到最后一个即可,可以证明其不超过 \(3B-1\)

  4. 排列

    逆天题。

    其实思路很简单,就是直接维护 \(min\)\(max\),在子树是否存在三元组,二元组中最大的最小和最小的最大。

    因为只有在不存在三元组时要维护二元组,直接子树二分即可。

    代码长,但还算好写。

posted @ 2024-08-21 21:23  xrlong  阅读(51)  评论(0)    收藏  举报

Loading