Codeforces Round #762 (Div. 3)

E. MEX and Increments
F. Let’s Play the Hat?
G. Unusual Minesweeper
H. Permutation and Queries


用个优先队列模拟。

map<int,int>ma;
priority_queue<int> q;

int main()
{
   	int t;
   	scanf("%d", &t);
   	while(t --)
   	{
   		int n;
   		scanf("%d", &n);
   		while(q.size())q.pop(); ma.clear();
   		q.push(-1);  // 初始不用特判,好像也没啥用 
		for(int i = 1;i <= n;i ++)
   		{
   			int x;
   			scanf("%d", &x);
   			ma[x] ++;
		}
		LL ans = 0;
		for(int i = 0;i <= n;i ++)
		{
			if(!q.size() || ans == -1)  
			{
				ans = -1, cout<<ans<<' ';
				continue;
			}
			else ans += i-1-q.top(), cout<<ans+ma[i]<<' ', q.pop(); // ans +的是 成为i-1,再加i的个数 
			while(ma[i]) q.push(i), ma[i]--;  // 加入队列。 
		}
		puts(""); 
	}
    return 0;
}

直接模拟

int now = 0, n;

void dp(int a, int b) // 产生 a 个 b人 的 桌子 
{
	for(int i = 1;i <= a;puts(""), i ++)
	{
		printf("%d", b);
		for(int i = 1;i <= b;now = (now+1)%n, i ++)
			printf(" %d", now+1);
	}
	return ;
}
int main()
{
   	int t;
   	scanf("%d", &t);
   	while(t --)
   	{
   		int m, k;
   		scanf("%d%d%d", &n, &m, &k);
   		int x = m-n%m, y = n/m;     // x 是下取整的桌子树 
   		int a = n%m, b = (n+m-1)/m; // a 是上取整的桌子数 
		now = 0;
   		while(k --)
   		{
   			int t;
   			dp(a, b); t = now;
   			dp(x, y); now = t; // 下一次游戏接着 上一次游戏的最后一个的下一个摆 
		}
	}
    return 0;
}

并查集合并 + 贪心,写的有点复杂

const int N = 3e5 + 10, mod = 998244353;

struct P{
	int x, y, id;
	bool operator < (const P& b)const{return x == b.x ? y < b.y : x < b.x;}
};
P a[N];
int fa[N], time[N];
int find(int u){return fa[u] == u ? u : fa[u] = find(fa[u]);}
void merge(int u, int v){fa[find(u)] = find(v);}

int main()
{
   	int t;
   	scanf("%d", &t);
   	for(int _ = 1;_ <= t;_ ++)
   	{
   		int n, k;
   		scanf("%d%d", &n, &k);
   		for(int i = 1;i <= n;i ++)
   		{
   			scanf("%d%d%d", &a[i].x, &a[i].y, time+i);
			a[i].id = i;	
			fa[i] = i;
		}
		sort(a+1, a+n+1);
		for(int i = 1;i < n;i ++)  // 按照x合并 
		{
			if(a[i].x == a[i+1].x && a[i+1].y <= a[i].y+k) 
				merge(a[i].id, a[i+1].id);
			swap(a[i].x, a[i].y);
		}
		swap(a[n].x, a[n].y);   // 这步在上面最后一次没到 n 需要加上。 
		sort(a+1, a+n+1);
		for(int i = 1;i < n;i ++)  // 按照y合并 
			if(a[i].x == a[i+1].x && a[i+1].y <= a[i].y+k) 
				merge(a[i].id, a[i+1].id);
				
		for(int i = 1, t;i <= n;i ++)
			if((t = find(i)) != i)
				time[t] = min(time[t], time[i]), time[i] = -1; // = -1代表不需要考虑 

		sort(time+1, time+n+1);
		int ans = -1, pos = n;
		while(pos)
			if(time[pos--] > ans) ans++;
			else break;
		printf("%d\n", ans);
	}
    return 0;
}

原来分块是这样写的啊,在链表上分块,jump[i]代表i进行block次next得到的位置,然后查询就是直接查询,修改那就是先把x和y改了,然后还需要改一些数字的jump[],这些数字就是x的前block个pre,y的前block的pre,好牛啊,卧槽。

int r[N], l[N], jump[N], block;

void change(int x)
{
	int to = x, i = block;
	while(i) to = r[to], i--;
	i = block;
	while(i) jump[x] = to, x = l[x], to = l[to], i --;	
}

int main()
{
   	int n, q;
   	scanf("%d%d", &n, &q);
   	for(int i = 1;i <= n;i ++) scanf("%d", r+i), l[r[i]] = i;
   	block = sqrt(n) + 1;
   	for(int i = 1;i <= n;i ++)
   	{
   		jump[i] = i;
		for(int j = 1;j <= block;j ++)	
			jump[i] = r[jump[i]];
	}
	while(q --)
	{
		int p, x, y;
		scanf("%d%d%d", &p, &x, &y);
		if(p == 1){
			swap(r[x], r[y]);
			l[r[x]] = x, l[r[y]] = y; // 先改 x, y 
			change(x), change(y);     // 再改 jump[] 
		}
		else{
			while(y >= block) x = jump[x], y -= block;
			while(y) x = r[x], y --;
			printf("%d\n", x); 
		}
	}
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李昌荣。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值