https://atcoder.jp/contests/abc252/tasks
G - Pre-Order
给一个n点多叉树的前序遍历结果, 问有多少个树满足, mod 998244353
其中子节点多个时, 按子节点数字从小到大遍历
范围
n 500
2s
1024mb
我的思路
当成父子结构时候, 顺序显然
所以感觉主要在兄弟结构
也就是现在 f(序列a)的方案数
f(a) = a[0]为根, a[1]为第一个树的根, a[i]为第二个树的根
f(a) = g(a[1…])
g(a) = sum f(a[0…i-1]) * g(a[i..])
其中a[0] < a[i]
整合一下 g(a) = sum g(a[1…i-1]) * g(a[i..]), a[0] < a[i]
似乎就没了
代码
https://atcoder.jp/contests/abc252/submissions/35211784
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include <bits/stdc++.h> #include <atcoder/modint> using mint = atcoder::modint998244353; using namespace std; typedef long long ll; #define rep(i,a,n) for (ll i=a;i<(ll)n;i++) ll read(){ll r;scanf("%lld",&r);return r;}
int a[510]; mint mem[510][510]; bool vis[510][510]; mint g(int l,int r){ if(l>=r)return 1; mint &v=mem[l][r]; if(vis[l][r]) return v; vis[l][r] = true; v = g(l+1,r); rep(i,l+1,r+1) if(a[l] < a[i]) v += g(l+1,i-1)*g(i,r); return v; }
int main(){ int n = read(); rep(i,0,n) a[i] = read(); printf("%d\n",g(1,n-1).val()); return 0; }
|
Ex - K-th beautiful Necklace
n个宝石
第i个颜色Di, 美丽值Vi
一共c个颜色, 每个颜色至少一个
要选C个两两不同颜色的宝石(顺序无关,顺序元素相同看作一种)
美丽值 = 它们的Vi的xor值
在所有有效的方案中对美丽值排序, 求第k大的美丽值
范围
1 <= c <= n <= 70
vi [0,2^60)
k [1,1e18]
2s
1024mb
我的思路
我好像, 连max都不会,怎么求k-th max
如果一个颜色只有一个,那么显然它被选,
显然 总方案数 = 每个颜色的个数 的乘积
问题是70能得到的最大乘积是啥?
2个一组的话
34359738368 = 2^35
125524238436 = 3^22 * 4
1000000000000000000 = 10^18
虽然没k上限那么大,但也不小
然后 还是从max开始考虑
xor + max
感觉只能从高到低贪心
可以容易计算出最高位, 为1的个数和0的个数
考虑为1的来源, 问题是
比如V为2 4
和5 3
交叉
那么得到 7 1 1 7
, 而并不能就划分成两块
因为 高位1 = 2x5, 4x3
按照高位划分, 会让记录的内容翻倍…
特别是当组不只两个的时候, 要按照高位为1/0 做切分
一个想法就是干脆不切分
直接统计 xor 高位是1和0的个数
如果确定要找的在1里面
再统计高位是10和高位是11的个数
假设在10里面,再100和101的个数
这样下降?
问题是 位多了以后,说是只统计10/11的个数,但在xor过程中依然需要记录01和00的个数
题解
Step1: 估计上限, 跟我上面做得一样 O(3^{N/3})
Step2: meet-in-the-middle
这… 1.3x1e11 叫faily small??????
哦 !!!!! 有道理
尽可能的对半分成 每个只需要O(3^{n/6}) 这样就大概,每个是1e5~1e6 个结果
Step3: 就是上面想的从高到低位做切割了, 这下只有两部分其实就好切割了
代码
https://atcoder.jp/contests/abc252/submissions/35213984
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| #include <bits/stdc++.h> using namespace std; typedef long long ll; #define rep(i,a,n) for (ll i=a;i<(ll)n;i++) #define per(i,a,n) for (ll i=n;i-->(ll)a;) #define sz(o) ((ll)(o).size()) ll read(){ll r;scanf("%lld",&r);return r;}
int main(){ int n = read(); vector<vector<ll> > V(read()); ll K = read(); rep(i,0,n){ int c=read()-1; V[c].push_back(read()); } sort(V.begin(),V.end(),[](const auto&v0,const auto&v1){return sz(v0)>sz(v1);}); array<vector<ll>,2> P{{ {0},{0} }}; rep(i,0,sz(V)){ int flag=(sz(P[0])>sz(P[1])); vector<ll> arr={}; for(auto v:V[i])for(auto x:P[flag]) arr.push_back(v^x); P[flag]=arr; }
ll ans=0; vector<array<vector<ll>,2> > A = {{ P[0],P[1] }}; per(B,0,60){ vector<array<array<vector<ll>,2>,2> > arr={}; ll cnt=0; for(auto ab:A){ array<array<vector<ll>,2>,2> nab = {{ {{ {},{} }},{{ {},{} }} }}; rep(i,0,2)for(ll x:ab[i]) nab[i][(x>>B)&1].push_back(x); arr.push_back(nab); rep(d,0,2)cnt+=sz(nab[0][d])*sz(nab[1][d^1]); } A={}; int bit; if(cnt<K){ K-=cnt; bit=0; } else { ans+=(ll)1<<B; bit=1; } for(auto &[a,b]:arr)rep(d,0,2)if(sz(a[d]) and sz(b[d^bit]))A.push_back({a[d],b[d^bit]}); } printf("%lld\n",ans); return 0; }
|
总结
G
没卡黄题
Ex
meet-in-middle , 我都试出了1.3e11 了 却没想到meet-in-middle 真是太菜了
参考
官方题解