【暑假集训】【模拟赛总结】lgjOI 7.14

68+100+35+0 = 203。 rk 10 左右吧。

第一题怒挂 32pts,像傻子。

T3

一道贪心。感觉考场上也推了和正解差不多的性质,但是总结出来的策略大大滴不对,没见过,我太菜。

如果把所有格子都用 x0+y0=kx_0+y_0= k 的斜线划分,会发现机器人只能沿着当前斜线走,或者跳到 x0+y0=k+2x_0+y_0=k+2。这个时候贪心来了:对于一个机器人 A,应该先吃同斜线的,吃不了的话就去另一条。可以大概理解一下:如果不吃,那么还需要至少一个机器人 B 处理斜线上的。但是如果机器人 A 走与 B 一样的路径,就可以省下来一段路了。

代码很简单:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
set<int>s[N];
int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int T; cin>>T;
	while(T --) {
		int n,m; cin>>n>>m;
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=m;j++) {
				char ch; cin>>ch;
				if(ch == '1') s[i+j].insert(i);
			}
		}
		int ans = 0;
		for(int i=1;i<=n+m;i++) {
			if(s[i+1].empty()) continue;
			int _i = i; ans++;
			for(int j=1;j<=n;j++) {
				s[_i+j].erase(j);
				if(!s[_i+j].empty() && *s[_i+j].rbegin() > j) _i--;
				else _i++;
			}
		}
		cout<<ans<<"\n";
	} 
	return 0;
}

T4 套路题

参考联合省选 2024 D1T2。看到异或,想想 01trie

以下的 dp 都是不考虑前缀的情况。比如数为 100111 时,考虑到第 4 个,就把数看成 000111

假定节点 uu 与他父亲节点连的边的权值放在了 uu 上,即 uu 代表了该位为 0/1。设 dpudp_u 为在 uu 的子树内选的方案数,会发现做不了,因为两个子树都选的情况无法统计。

归根结底,不可做是因为不知道子树的子树的情况,那我们手动选择两个子树呢?

dpx,ydp_{x,y} 要求在这两个子树表示的数来选(两个子树都强制取)的方案数。

XXx,yx,y 的儿子这一位上为 0 的时候,显然不能选异侧的子树,答案即为 dplx,ly+dprx,rydp_{lx,ly} + dp_{rx,ry}

XXx,yx,y 的儿子这一位上为 1 的时候(以下设 xx 随便选为 s(x)s(x),根据题意也就是 2sz(x)12^{sz(x)}-1):

如果 x,yx,y 是一个节点,“两个子树”其实就是一个子树。同侧可以随便选,异侧的答案就是 dplx,rxdp_{lx,rx}

如果不是。我们可以分成这三类:选 2,3,42,3,4 个子树进行统计(lxlx 表示 xx 的左子树,其他同理)。

  • 两个子树:因为限制,所以只能是两个子树的 lx,lylx,lyrx,ryrx,ry 随便选,和考虑将 lx,rylx,ryly,rxly,rx dp。

  • 三个子树:那就是两个是 lx,lylx,ly,一个 ryrylx,rylx,ry 已经知道了。会发现 lx,lylx,lyly,ryly,ry 因为相同值异或为 00,都是随便选的状态。所以答案即为 dplx,ry×(s(ly)+s(rx))+dply,rx×(s(lx)+s(ry))dp_{lx,ry} \times(s(ly)+s(rx)) + dp_{ly,rx} \times(s(lx)+s(ry))

  • 四个子树:那全部都要选:x,yx,y 这一位肯定会是 11。就要考虑剩下的情况,而事实上,只有 lx,rylx,ryly,rxly,rx 这种会互相限制,所以答案就是 dplx,ry×dply,rxdp_{lx,ry}\times dp_{ly,rx}

为什么能这么做?总而言之,是因为限制的情况只有 lx,rylx,ryly,rxly,rx。正是因为 相同值异或为 00 这一性质,才不会使复杂度爆炸。复杂度即为 01trie 的节点个数 nlognn\log n

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5+10, mod = 998244353;
struct M{
	int sz,ch[2];
}t[N*22];
int n,a[N],T;
int mi(int x,int k) {int p; return k?p=mi(x,k>>1),p*p%mod*(k&1?x:1)%mod:1;}

int s(int x){
	return (mi(2,t[x].sz) - 1 + mod) % mod;
}
int idx,rt;
void ins(int &p,int x,int k) {
	if(p == 0) p = ++idx;
	t[p].sz ++;
	if(k < 0) return ;
	ins(t[p].ch[((x&(1<<k)) > 0)],x,k-1);
}
int dp(int x,int y,int k) {
	if(x == 0 || y == 0) {
		return 0;
	}
	if(k < 0) {
      //这个是叶子节点的情况:也就是说第 0 位 0/1
      //如果我们回到上一位的视角,你就会发现限制什么的其实不存在,所以这个随便选是对的
		if(x == y) return s(x);
		return s(x) * s(y) % mod;
	}
	#define xls t[x].ch[0]
	#define xrs t[x].ch[1]
	#define yls t[y].ch[0]
	#define yrs t[y].ch[1]

	if((T & (1 << k)) == 0) {
		return (dp(xls,yls,k-1) + dp(xrs,yrs,k-1)) % mod;
	}
	
	if(x == y) {
		return (dp(xls,xrs,k-1) + s(xls) + s(xrs)) % mod;
	}
	int ans = 0, k1 = dp(xls,yrs,k-1), k2 = dp(xrs,yls,k-1);
	ans += s(xls) * s(yls) % mod + s(xrs) * s(yrs) % mod; // 同左, 同右
	ans += k1 + k2;
	ans += s(xls) * k2 % mod + s(yrs) * k2 % mod + s(xrs) * k1 % mod + s(yls) * k1 % mod;
	ans += k1 * k2 % mod;
	return ans % mod;
}
signed main() {
	cin>>n>>T;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) ins(rt,a[i],30);
	cout<<dp(rt,rt,30);
	return 0;
}
posted @ 2024-07-15 16:06  cjrqwq  阅读(10)  评论(0)    收藏  举报  来源