首页 > 其他分享 >atcoder 杂题 #04

atcoder 杂题 #04

时间:2024-12-19 21:58:24浏览次数:4  
标签:atcoder fu 04 int top 异或 区间 矩形 杂题

atcoder 杂题 #04

abc126_f

挺有意思的一道题,让我猜到结论了。

由于长度是值域的两倍,所以不难想到每个数出现两次,不然发现对于 \(a_i=a_j=a_k\) 的三个数,当 \(a_i\oplus \cdots\oplus a_j=a_j\oplus \cdots\oplus a_k=K\) 时,一定有 \(a_i\oplus \cdots\oplus a_k=a_j=K\),此时就无法构造了。

首先 \(K=0\) 的情况就是 \(0,0,1,1,\cdots,2^m-1,2^m-1\)。
对于 \(K\ge2^m\) 则无解。

由于我们要让异或和为 \(K\),不妨让 \(K\) 放中间,然后每次往两边添加两个相同的数,最后在一边再添加 \(K\),这就要求 $ \oplus_{i=0}{2m-1} i=0$,才能使两个 \(K\) 之间的异或和为 \(K\)。
即形如 \(0,1,2,\cdots ,2^m-1,K,2^m-1,\cdots,2,1,0,K\)。

做这道题的时候认为异或和不为 0 就是无解。
但写到这才发现由于范围是 \(0\sim 2^m-1\),所以异或和必定为 0,所以我们的构造方式是正确的。

AC 代码:

int n,m;
signed main(){
	cin>>n>>m;
	if(m==0){
		fu(i,0,1<<n)cout<<i<<' '<<i<<" ";
		return 0;
	}
	int s=0;
	fu(i,0,1<<n)s^=i;
	if(s==0&&m<(1<<n)){
		fu(i,0,1<<n)if(i!=m)cout<<i<<" ";
		cout<<m<<" ";
		fd(i,(1<<n)-1,0)if(i!=m)cout<<i<<" ";
		cout<<m<<" ";
		return 0;
	}
	else cout<<"-1";
	return 0;
}

arc081_d

没有想出来。

其实是一个经典结论,考虑怎样的矩形满足可以经过翻转行和列使得变成全 1 的矩形。

结论就是,如果一个矩形内所有 \(2\times 2\) 的子矩形中 1 和 0 都是偶数个(即异或和为 0),那么这个矩形就是合法的。

证明:
对于一个 \(n\times m\) 的矩形,有 \(2^{n+m}\) 个矩形满足可以从全 1 的矩形得到,这些矩形都是合法的。
我们又发现,合法的矩形一定满足每行都与第一行每位相同或每位相反,列也同理。因为从全 1 矩形开始操作,无论怎么操作都满足这个性质。
于是每行也与上一行每位相同或每位相反,因此可以得到,合法的矩形满足每个 \(2\times 2\) 的矩形异或和为 0。
这就证明了必要性,充分性呢?
发现如果确定了第一行和第一列,那么根据 \(2\times 2\) 子矩形异或和为 0 的性质,其他位置也都确定了。
而确定第一行和第一列的方式恰好是 \(2^{n+m}\) 种,于是每一种满足 \(2\times 2\) 子矩形异或和为 0 的矩形,都是合法矩形。

然后怎么做呢?

考虑根据每一个 \(2\times 2\) 的子矩形是否合法构造一个新的矩阵,然后就是求面积最大的子矩阵,这是经典问题,可以使用单调栈在 \(O(n^2)\) 解决。

AC 代码:

const int N=2005;
char a[N][N];
int c[N][N];
int n,m;
pair<int,int> stk[N];
int top,l[N],r[N];
signed main(){
	read(n,m);
	fo(i,1,n)fo(j,1,m)read(a[i][j]);
	fu(i,1,n)fu(j,1,m){
		int x=a[i][j]^a[i+1][j]^a[i][j+1]^a[i+1][j+1];
		if(x==0)c[i][j]=c[i-1][j]+1;
	}
	int ans=max(n,m);
	fu(i,1,n){
		top=0;
		fu(j,1,m){
			l[j]=r[j]=j;
			while(top&&stk[top].first>=c[i][j])--top;
			l[j]=stk[top].second;
			stk[++top]={c[i][j],j};
		}
		stk[top=1]={-1,m};
		fd(j,m-1,1){
			while(top&&stk[top].first>=c[i][j])--top;
			r[j]=stk[top].second;
			stk[++top]={c[i][j],j};		
			if(c[i][j])ans=max(ans,(c[i][j]+1)*(r[j]-l[j]));
		}
	}
	write(ans);
	return 0;
}

arc080_c

好题。

首先这种字典序最小就是贪心,由于每次是往前面加,所以考虑倒序。

考虑如果选择 \(i,j(i<j)\),那么在正序时就表现其他都选完了后,再选了它们。

那么第一次选择 \(i,j\) 合法当且仅当 \([1,i-1],[i+1,j-1],[j+1,n]\) 都是偶数长度。

则 \(i\) 为奇数,\(j\) 为偶数。

发现这三个区间的问题是互相独立的,可以递归求解。

每次在 \([L,R]\) 选择 \(i,j\) 就要满足 \(i\) 和 \(L\) 的奇偶性相同,\(j\) 和 \(L\) 的奇偶性不同。

考虑怎么快速求出一个区间内最优的 \(i,j\)。

贪心地,选出奇数(或偶数)位上最小的数作为 \(i\),由于区间长度是偶数,\(i\) 后面一定至少选出一个 \(j\),把 \(i\) 后面与 \(i\) 奇偶性不同的位中取最小值作为 \(j\) 即可,可以用 ST 表维护奇数(偶数)位的区间最小值,同时也可以得到最小值所在的位置。

考虑怎么合并每个子区间,发现直接合并类似于归并的过程,然而每次的时间都是合并的两个区间长度之和,时间复杂度不能接受。

考虑求出所有 \(i,j\) 对后,从大区间往小区间做。开始 \([1,n]\) 的 \(i,j\) 对丢进堆里,每次从堆里选完一个区间 \(i,j\) 后,把每个子区间的 \(i,j\) 丢进堆里,因为子区间要在父区间之后选。

时间复杂度的瓶颈在于预处理 ST 表和最后的堆,为 \(O(n\log n)\)。

AC 代码:

const int N=2e5+5;
int n;
int a[N];
struct S_list{
	pair<int,int> mn[18][N];
	pair<int,int> get(int l,int r){
		int len=r-l+1;
		return min(mn[__lg(len)][l],mn[__lg(len)][r-(1<<__lg(len))+1]);
	}
	void make(){
		fo(i,1,__lg(n)){
			fo(j,1,n-(1<<i)+1){
				mn[i][j]=min(mn[i-1][j],mn[i-1][j+(1<<i-1)]);
			}
		}
	}
}s[2];
vector<int> g[N];
int ans1[N],ans2[N];
int tot;
int solve(int l,int r){
	int x=++tot;
	int opt=l&1;
	auto t1=s[opt^1].get(l,r);
	auto t2=s[opt].get(t1.second+1,r);
	ans1[x]=t1.first,ans2[x]=t2.first;
	if(t1.second>l)g[x].push_back(solve(l,t1.second-1));
	if(t1.second+1<t2.second)g[x].push_back(solve(t1.second+1,t2.second-1));
	if(t2.second<r)g[x].push_back(solve(t2.second+1,r));
	return x;
}
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<> > q;
signed main(){
	cin>>n;
	fo(i,1,n){
		cin>>a[i];
		s[0].mn[0][i]=s[1].mn[0][i]={N,N};
		if(i&1)s[0].mn[0][i]={a[i],i};
		else s[1].mn[0][i]={a[i],i};
	}
	s[0].make(),s[1].make();
	solve(1,n);
	q.push({ans1[1],1});
	while(q.size()){
		int u=q.top().second; q.pop();
		cout<<ans1[u]<<" "<<ans2[u]<<' ';
		for(auto v:g[u]){
			q.push({ans1[v],v});
		}
	}
	return 0;
}

abc383_g

若干个经典结论。

我们先把每 \(K\) 个数的和构成一个新的数组,要求对每个 \(x\) 求出选 \(x\) 个数且两两之间必须间隔 \(K-1\) 个数,问最大和。

考虑分治,我们对于每个区间 \([L,R]\) 求出 \(f_{i,j,k}\) 表示区间左边有 \(i\) 个数没选,右边有 \(j\) 个数没选,选了 \(k\) 个数且这些数已合法的最大和。

那么我们枚举 \(i,j\) 后考虑合并两个区间的数组,每个数组都是一个值关于 \(k\) 的上凸函数,感性理解就是选的越多加的越少。

合并两个凸函数可以做到 \(O(Len)\),其中 \(Len\) 是定义域。这是一个经典结论,具体地,如果我们知道 \(f_i+g_j\to h_{i+j}\) 是转移到 \(i+j\) 最优的 \(i,j\),那么转移到 \(h_{i+j+1}\) 最优的 \(i,j\) 一定是 \(f_{i+1}+g_{j}\) 或 \(f_{i}+g_{j+1}\),取最大的作为新的 \(i,j\) 即可。

计算时间复杂度,枚举两边每选的 \(O(K^2)\),枚举中间没选的 \(O(K)\),因为两个区间中间没选的和为 \(K-1\),枚举一个即可。然后枚举选的个数 \(O(\frac n K)\),再乘上分治的 \(O(\log n)\) 层。
于是总的就是 \(O(n K^2\log n)\)。

AC 代码:

const int N=2e5+5;
const ll inf=0x3f3f3f3f3f3f3f3fll;
int n,K;
int a[N];
ll b[N];
struct arr{
	vector<ll> f[5][5];
};
void mx(ll &x,ll y){
	x=max(x,y);
}
void solve(arr &x,int l,int r){
	int sz=(r-l+K)/K+1;
	fu(i,0,5)fu(j,0,5)x.f[i][j]=vector<ll>(sz,-inf);
	if(l==r){
		x.f[0][0][1]=b[l];
		return;
	}
	arr L,R;
	int mid=(l+r)>>1;
	int ls=(mid-l+K)/K+1,rs=(r-mid-1+K)/K+1;
	solve(L,l,mid),solve(R,mid+1,r);
	fu(i,0,5)fu(j,0,5){
		fu(p,1,sz){
			if(p<ls)mx(x.f[i][min(4,j+r-mid)][p],L.f[i][j][p]);
			if(p<rs)mx(x.f[min(4,i+mid-l+1)][j][p],R.f[i][j][p]);
		}
		fu(k,0,K){
			int y=0,z=0;
			fu(p,1,sz){
				if(y+1==ls)++z;
				else if(z+1==rs)++y;
				else if(L.f[i][k][y+1]+R.f[K-1-k][j][z]>L.f[i][k][y]+R.f[K-1-k][j][z+1])++y;
				else ++z;
				if(y<ls&&z<rs)mx(x.f[i][j][p],L.f[i][k][y]+R.f[K-1-k][j][z]);
			}
		}
	}
	fd(i,4,0)fd(j,3,0)fu(p,1,sz)mx(x.f[i][j][p],x.f[i][j+1][p]);
	fd(j,4,0)fd(i,3,0)fu(p,1,sz)mx(x.f[i][j][p],x.f[i+1][j][p]);
}
signed main(){
	cin>>n>>K;
	fo(i,1,n)cin>>a[i];
	fo(i,K,n)fo(j,i-K+1,i)b[i]+=a[j];
	arr Main;
	solve(Main,K,n);
	fo(i,1,n/K){
		ll ans=-inf;
		fu(j,0,5)fu(k,0,5)mx(ans,Main.f[j][k][i]);
		cout<<ans<<' ';
	}
	return 0;
}

标签:atcoder,fu,04,int,top,异或,区间,矩形,杂题
From: https://www.cnblogs.com/dccy/p/18618006

相关文章

  • U504405 破译诸葛亮的密码箱
    题目背景在《三国演义》中,诸葛亮以其卓越的智慧和深思熟虑的战略而著称。某日,诸葛亮在蜀汉准备重要军事行动时,为了确保信息安全,他将一份机密文件放到一个密码箱里面,并设置了一道谜题,只有解出谜题才能知道密码。题目描述诸葛亮有一棵有 n个顶点的树。初始时,所有顶点都是白......
  • 【区间dp】p1004方格取数
    一、问题描述设有 N×NN×N 的方格图 (N≤9)(N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 00。如下图所示(见样例):图1某人从图的左上角的A点出发,可以向下行走,也可以向右走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为......
  • 题解:P10483 小猫爬山
    思路第一眼我以为是个背包,但由于是分组,所以有多个缆车,明显不能用背包。我做这题是因为老师要求,那是我们在学深搜减枝,所以我就开始写深搜。这一题实际上是先选一直最重的猫,然后搞个\(sum\)数组,每搞一个新缆车的就下一个下标继续放,如果能放就放,当然也要搞一个能放但不放的。减枝......
  • w104学生网上请假系统
    ......
  • vue3使用axios请求接口,先报错301,然后报错404
    一、问题描述在开发项目需求的时候,碰到一个奇怪的错误,先报错301,然后报错404,如上图所示。但是项目的其他接口请求都是正常的。二、错误原因及解决方法接口url的末尾缺少斜杠/,加上就好了。原url:‘/userproject’现url:‘/userproject/’......
  • 804 石子游戏 II
    //804石子游戏II.cpp:此文件包含"main"函数。程序执行将在此处开始并结束。///*http://oj.daimayuan.top/course/22/problem/738Alice和Bob正在玩一个关于石子的游戏。共有n堆石子,其中第i堆最初含有ai个石子。他们轮流执行下列操作之一,从Alice开始。把......
  • 20222404 2024-2025-2 《网络与系统攻防技术》实验八实验报告
    1.实验内容(1)Web前端HTML能正常安装、启停Apache。理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML。(2)Web前端javascipt理解JavaScript的基本功能,理解DOM。在(1)的基础上,编写JavaScript验证用户名、密码的规则。在用户点击登陆按钮后回显“欢迎+输入的用户名”尝......
  • IEC104中为什么我们需要单点和双点信号
    REDISANT提供互联网与物联网开发测试套件 #互联网与中间件:RedisAssistantZooKeeperAssistantKafkaAssistantRocketMQAssistantRabbitMQAssistantPulsarAssistantHBaseAssistantNoSqlAssistantEtcdAssistantGarnetAssistant工业与物联网:MQTTAssis......
  • SSM大学生兼职系统—免费源码分享04443
    目录1绪论1.1选题背景与意义1.2国内外研究现状1.3论文结构与章节安排2系统分析2.1可行性分析2.1.1技术可行性分析2.1.2经济可行性分析2.1.3操作可行性分析2.2系统流程分析2.2.1添加信息流程2.2.2修改信息流程2.2.3删除信息流程2.3 系统功......
  • 【内向基环树】codeforces 2044 G1. Medium Demon Problem (easy version)
    前言基环树,又名环套树,是具有\(n\)个节点和\(n\)条边的图,比树多出现一个环。基环树也根据边的有向和无向分为了有向基环树和无向基环树。有向基环树又可以分为内向基环树和外向基环树。对于有向基环树,若基环树的每个节点的出度均为\(1\),则称为内向基环树;若基环树的每个节点的......