AtCoder Regular Contest 182(A B C)

原来第二题比第一题简单吗😢

A.Chmax Rush! Diff 1110

给定三个序列 S,P,V,其中 S 的长度为 NP,V 的长度为 Q,按从小到大的顺序对每个 i[1,Q] 执行下述操作:

[1,Pi][Pi,N] 中选择一个区间,要求其中所有的值都不大于 Vi,然后将区间内所有值替换成 Vi

求出能在符合要求的情况下执行全部操作的方案数

N,Q5000

Hint

离线下来倒序做

Solution

考虑到可以倒序做这个题.

假设现在我们枚举到了操作 i,那么,对于它前面的每一个操作 j,假如 Vi<Vj,显然这两个操作就不能有重复区间了. 那么如何才能让它们之间没有重复区间?分以下情况讨论:

  • Pi<Pj,为了无交集,应该选 [1,Pi],[Pj,N] 两个区间

  • Pi>Pj 同理,选 [1,Pj],[Pi,N] 两个区间

  • Pi=Pj,无论如何选总会在 Pi 相交,直接判无解

因此此题可以 n2 做,鉴于单次操作可能的状态只有两个,因此记录一下谁放右边,谁放左边就行了. 最后加起来一乘就是答案.

Code
int n,q,p[5001],v[5001],s[5001],ans=1;
const int mod=998244353;
bool isleft[5001],isright[5001];
int main(){
	read(n,q);
	for(int i=1;i<=q;++i){
		read(p[i],v[i]);
		isleft[i]=isright[i]=true;
	}
	for(int i=q;i>=1;--i){
		for(int j=i-1;j>=1;--j){
			if(v[i]<v[j]){
				if(p[i]>p[j]){
					isleft[i]=false;
					isright[j]=false;
				}
				else if(p[j]>p[i]){
					isright[i]=false;
					isleft[j]=false;
				}
				else{
					printf("0\n");
					return 0;
				}
			}
		}
		if(!isleft[i] and !isright[i]){
			printf("0\n");
			return 0;
		}
		ans=ans*(isright[i]+isleft[i])%mod;
	}
	printf("%d\n",ans);
}

B.|{floor(A_i/2^k)}| Diff 1049

给定 N,K,构造一个长为 N 的序列,满足序列元素范围在 [1,2K1] 之间

定义序列价值如下:对于全部的非负整数 k,序列中 Ai2k 的不同值个数

如序列 {3,5},当 k=0 时不同的值个数为 2{3,5}),当 k=1 时为 2{1,2}),k=2 时只有一个新元素出现 ({0,1}),和为 5

请你最大化构造出来的序列的价值

N2×105,K30

Solution

发现这个 Ai2k 的操作非常像右移啊,其实就相当于 AiRshk

也就是说要构造一下任意次右移得到的结果最多的序列.

首先考虑到一个更优的 Ai 满足什么条件. 可以想到 2Ai 总是比 Ai 更优,不仅拥有 Ai 的全部情况,且总是比 Ai 要多一个情况: 2Ai,因此我们只需要考虑在 [2K1,2K) 范围内的数字即可.

N>2k1 的时候,直接全部都取一遍就行了.

否则,有一结论:答案的上界为 1+x=0K1min(N,2x)

证明:考虑每一个区间 [2x,2x+1),可以发现,对于每一个 Ai,它进行操作后最多只有一个数能落在此区间内,而我们有 N 个数,因此此区间最大值即为 N,同时,考虑到 N 可能比区间内的数字总和要大,因此最终每个区间的贡献为 min(N,2x),再加上不在这些区间里的一个贡献 0,总和就是 1+x=0K1min(N,2x)

本题的关键不在此处,而是如何去构造一个满足条件的数列.

定义 br(x) 表示 xK1 位二进制表示下的反串,即如果 K=7,x=5,那么 x=000101(2)br(x)=101000(2)

那么按如下操作构造该序列:

Ai=2K1+br(i)

即可.

根据刚才的证明,可以发现,要达到这个上界,只需要让构造出来的数字满足 i,jbitk(i)bitk(j),其中 bitk(i) 表示 i 的二进制表示中的最高 k 位. 可以发现自然数的反串满足这个条件:对于 ij=2k,总是存在 bitk1 使其不同,而二进制反串有很多个,为了使最后的答案取到区间 [2K1,2K) 范围内的数,因此我们才构造出 K1 位的反串,这样做可以使得到的数字最大为 2K1+2K11=2K1,恰好满足条件.

Code
#include<bits/stdc++.h>
using namespace std;
int n,k,t;
int br(int x){
	int ans=0;
	for(int i=1;i<=k-1;++i){
		ans=ans*2+x%2;
		x/=2;
	}
	return ans;
}
int main(){
	cin>>t;
	while(t--){
		cin>>n>>k;
		if(n>=(1<<(k-1))){
			for(int i=1;i<=n;++i){
				cout<<max(1,(1<<k)-i)<<" ";
			}
		}
		else{
			for(int i=1;i<=n;++i){
				cout<<(1<<(k-1))+br(i)<<" ";
			}
		}
		cout<<endl;
	}
}

C.Sum of Number of Divisors of Product Diff 2408

给定 N,M,求下述式子的值:

i1=1Mi2=1MiN=1Mf(j=1Nij)

其中 f(x) 定义为 x 的不同正因子个数

N1018,M16

Solution

首先你需要知道 f(x) 怎么求,如果你不知道的话请移步 此文章4.5

考虑到 16 以内的质数只有六个,即对任意一个 j=1Nij,都可以表述为如下形式:

2a13a25a37a411a513a6

因此我们成功将题意转化为求 i=16(ai+1)

然后 DP 做?但是我不知道 DP 怎么做

if anyone known, then teach me plz

posted @   HaneDaniko  阅读(130)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示