模拟赛25
最近怎么狂挂不止。
-
博弈
考虑策略,首先是优先最小的,但是由于有重复的,所以在最小个数为偶数时会败,以此类推,可以想到当有一个数出现次数时奇数先手必胜,否则必败。
考虑将相同的两两相消,发现 \(u\to v\) 和 \(u\to 根\to v\) 是等价的。
于是每个点维护一下当前的数,问题变成了求和当前集合相同的集合有几个,因为两两相消,可以异或 hash,也可用一些奇怪 hash。
但是千万千万不要直接用 \(\sum a^n\),这个东西竟然是可以稳定被卡的!
-
跳跃
发现其一定是在一个最大子段中反复横跳,然后在到下一个。
数据比较水,错解轻松过(于是加了 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; } } }
-
大陆
水题,建议改名:树分块前置。
就是考虑维护子树中没有被选的,合并到父亲上,如果 \(\ge B\) 就单开一个,以父节点为省会。
最后的根直接归到最后一个即可,可以证明其不超过 \(3B-1\)。
-
排列
逆天题。
其实思路很简单,就是直接维护 \(min\),\(max\),在子树是否存在三元组,二元组中最大的最小和最小的最大。
因为只有在不存在三元组时要维护二元组,直接子树二分即可。
代码长,但还算好写。