首页 > 其他分享 >春季测试2023全题解

春季测试2023全题解

时间:2023-03-06 12:13:14浏览次数:43  
标签:max min int 题解 ll mid 春季 -- 2023

T1 涂色游戏

非常困难的题目,我们需要记录每一行/每一列最后一次被修改的时间以及被修改成什么颜色。

输出的时候每一个格子是受行影响还是列影响即可。复杂度 \(O(nm)\)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int BS=1<<20|5;
char buf[BS],*P1,*P2;
inline char gc(){
	if(P1==P2)P2=(P1=buf)+fread(buf,1,BS,stdin);
	return P1==P2?EOF:*(P1++);	
}
inline int in(){
	int x=0,f=1;char ch=gc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=gc();
	return x*f;
}
typedef pair<int,int> P;
const int N=1e5+5;
int n,m,q;
P a[N],b[N];
void solve(){
    n=in(),m=in(),q=in();
    for(int i=1;i<=n;i++)a[i]=make_pair(0,0);
    for(int i=1;i<=m;i++)b[i]=make_pair(0,0);
    for(int i=1;i<=q;i++){
        int op=in(),x=in(),y=in();
        if(!op)a[x]=make_pair(i,y);
        else b[x]=make_pair(i,y);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            printf("%d%c",max(a[i],b[j]).second,j==m?'\n':' ');
    	}
    }
}
int main(){
	freopen("paint.in","r",stdin);
	freopen("paint.out","w",stdout);
	int T=in();
    while(T--)solve();
    return 0;
}

T2 幂次

可以被写成 \(a^b\) 的不超过 \(n\) 的数很明显有 \(\lfloor n^{\frac 1 b} \rfloor\) 个,这个可以二分出来,记为 \(F(b)\)。但是答案很明显不是把所有 \(F\) 加起来(这样会算重)。为了不算重,我们记 \(G(b)\) 为 可以被写为 \(a^b\) 且不能被写成 \(a'^{b'},b'>b\) 的数的数量。这下每个数就只会贡献一次,答案就是 \(G\) 的和。然后考虑 \(F\) 和 \(G\) 的关系,不难发现 \(F(i)=\sum_{i|j} G(j)\),于是我们把 \(G\) 容斥出来就行了。

时间复杂度 \(O(k \log n+k \log k)\)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int in(){
	int x;
	scanf("%d",&x);
	return x;
}
ll n,k;
ll f[105];
ll pw(ll x,int k){
	__int128 y=1;
	for(int i=1;i<=k;i++){
		y*=x;
		if(y>n){y=n+1;break;}
	}
	return (ll)y;
}
ll calc(int k){
	ll l=1,r=n,mid;
	while(l<=r){
		mid=l+r>>1;
		if(pw(mid,k)<=n)l=mid+1;
		else r=mid-1;	
	}
	return l-2;
}
int main(){
	freopen("power.in","r",stdin);
	freopen("power.out","w",stdout);
	cin>>n>>k;
	ll ans=1;
	for(int i=k;i<60;i++){
		f[i]=calc(i);
	}
	for(int i=59;i>=k;i--){
		for(int j=i+i;j<60;j+=i)f[i]-=f[j];
		ans+=f[i];
	}
	cout<<ans<<endl;
	return 0;
}

T3 圣诞树

我们需要发现关键性质:路径不会自交。发现这一性质以后,可以推出,我们路径的一段前缀对应在环上,一定是一段区间(如果不是一段区间,那么以后来填空的时候一定会自交),于是可以列出 dp 状态 \(f_{l,r,0/1}\),表示当前的区间是 \(l,r\),最后一步是在 \(l\) 还是 \(r\)。然后讨论是 \(l-1\) 还是 \(r+1\) 来转移,转移的时候记录前驱状态,就可以打印方案了。

那么如何证明路径不会自交呢?考虑基本的情况:只有四个点。

style="zoom:50%;"

其中红色的路径不自交,蓝色的路径自交,两者不同的位置是两个绿色的三角形,由三角形两边之和大于第三边可得蓝色路径一定更长。
而点更多的情况一定可以归纳到若干四个点的基本情况,所以路径自交一定不优。

综上,直接区间 dp,复杂度 \(O(n^2)\)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
inline int in(){
	int x;
	scanf("%d",&x);
	return x;
}
const int N=1005;
int n,k;
db px[N],py[N];
db dis(int a,int b){
	a%=n,b%=n;
	return sqrt((px[a]-px[b])*(px[a]-px[b])+(py[a]-py[b])*(py[a]-py[b]));	
}
pair<db,int> f[3005][3005][2];
int main(){
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	scanf("%d",&n);
	db mx=-1e18;
	for(int i=0;i<n;i++){
		scanf("%lf%lf",px+i,py+i);
		if(py[i]>mx)mx=py[i],k=i;
	}
	for(int i=0;i<3*n;i++)
		for(int j=0;j<3*n;j++)
			f[i][j][0]=f[i][j][1]=make_pair(1e18,0);
	f[k+n][k+n][0]=make_pair(.0,0);
	for(int d=1;d<n;d++){
		for(int l=k+n,r=k+n+d-1;r>=k+n;l--,r--){
			f[l-1][r][0]=min(f[l-1][r][0],make_pair(f[l][r][0].first+dis(l-1,l),0));
			f[l-1][r][0]=min(f[l-1][r][0],make_pair(f[l][r][1].first+dis(l-1,r),1));
			f[l][r+1][1]=min(f[l][r+1][1],make_pair(f[l][r][0].first+dis(r+1,l),0));
			f[l][r+1][1]=min(f[l][r+1][1],make_pair(f[l][r][1].first+dis(r+1,r),1));
		}
	}
	db mn=1e18;int id=0;
	for(int l=k+1;l<=k+n;l++){
		if(f[l][l+n-1][0].first<mn)mn=f[l][l+n-1][0].first,id=l<<1;
		if(f[l][l+n-1][1].first<mn)mn=f[l][l+n-1][1].first,id=l<<1|1;
	}
	int l=id>>1,r=l+n-1,c=id&1;
	vector<int> v;
	while(l<=r){
		int c1=f[l][r][c].second;
		if(!c)v.push_back(l%n),l++;
		else v.push_back(r%n),r--;
		c=c1;	
	}
	reverse(v.begin(),v.end());
	for(int x:v)printf("%d ",x+1);puts("");
	return 0;
}

T4 密码锁

\(k=1\):直接输出 \(max-min\)。

\(k=2\) :把每列的 \(min\) 放第一行,\(max\) 放第二行,可以发现这样一定不劣,然后直接计算答案。

对于 \(k=3,4\) 的情况,我们可以先二分答案,然后枚举每一行的 \(min\),这下每行的区间都已确定,就可以 check 是否可行。这个暴力是自然的,复杂度 \(O((nk)^{k+1})\)。并不能拿到多少分,但是在此基础上,我们可以想到,必定有一行的 \(min\) 是全局 \(min\),还有另外一行的 \(max\) 是全局 \(max\) (只有最坏的情况全局 \(min\) 和 \(max\) 会放在同一行)。我们钦定第一行是全局 \(min\),然后枚举哪一行是全局 \(max\),于是这样就有两行的区间确定了,我们只需要考虑剩下的 \(k-2\) 行。

当 \(k=3\) 相当于数轴上有若干个点,一共有 \(n\) 种颜色,问是否有一段长度为 \(mid\) 的区间可以覆盖所有颜色。可以直接双指针判断。

当 \(k=4\) 相当于二维平面上有若干个点,一共有 \(n\) 中颜色,问是否有一段大小为 \(mid \times mid\) 的矩形可以覆盖所有颜色。然后我们对 \(x\) 这一维双指针,然后对 \(y\) 这一维线段树。为了一种颜色不被算重,需要做一些特殊处理,在此就各显神通了。

复杂度 \(O(\sum n \log^2 n)\)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int BS=1<<20|5;
char buf[BS],*P1,*P2;
inline char gc(){
    if(P1==P2)P2=(P1=buf)+fread(buf,1,BS,stdin);
    return P1==P2?EOF:*(P1++);
}
inline int in(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){ch=gc();if(ch=='-')f=-1;}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=gc();
    return x*f;
}
const int N=1e5+5,inf=1e9;
int n,k;
int a[N][4];
namespace solve1{
	void main(){
		n=in();
		int mn=inf,mx=0;
		for(int i=1;i<=n;i++){
			a[i][0]=in();
			mn=min(mn,a[i][0]);
			mx=max(mx,a[i][0]);
		}
		printf("%d\n",mx-mn);
	}
}
namespace solve2{
	void main(){
		n=in();
		for(int j=0;j<2;j++)
			for(int i=1;i<=n;i++)
				a[i][j]=in();
		int mn0=inf,mx0=0,mn1=inf,mx1=0;
		for(int i=1;i<=n;i++){
			if(a[i][0]>a[i][1])swap(a[i][0],a[i][1]);
			mn0=min(mn0,a[i][0]),mx0=max(mx0,a[i][0]);
			mn1=min(mn1,a[i][1]),mx1=max(mx1,a[i][1]);
		}
		printf("%d\n",max(mx0-mn0,mx1-mn1));
	}
}
namespace solve3{
	int mn,mx;
	int cnt[N],buc[3];
	bool check(int mid){
		vector<pair<int,int> > v;
		for(int i=1;i<=n;i++){
			bool flag=0;
			for(int j=0;j<3;j++){
				if((a[i][(j+1)%3]>mn+mid||a[i][(j+2)%3]<mx-mid))continue;
				v.push_back(make_pair(a[i][j],i));
			}
		}
		sort(v.begin(),v.end());
		int m=v.size();
		for(int i=1;i<=n;i++)cnt[i]=0;buc[0]=n;
		for(int l=0,r=0;r<m;l++){
			for(;r<m&&v[r].first<=v[l].first+mid;r++){
				int &x=cnt[v[r].second];buc[x]--,buc[++x]++;
			}
			if(!buc[0])return 1;
			int &x=cnt[v[l].second];buc[x]--,buc[--x]++;
		}
		return 0;
	}
	bool check1(int mid){
		if(check(mid))return 1;
		for(int i=1;i<=n;i++)swap(a[i][0],a[i][1]);
		return check(mid);
	}
	void main(){
		n=in();
		mn=inf,mx=0;
		for(int j=0;j<3;j++)
			for(int i=1;i<=n;i++){
				a[i][j]=in();
				mn=min(mn,a[i][j]);
				mx=max(mx,a[i][j]);
			}
		int l=0,r=mx-mn,mid;
		while(l<=r){
			mid=l+r>>1;
			if(check1(mid))r=mid-1;
			else l=mid+1;
		}
		printf("%d\n",r+1);
	}
}
namespace solve4{
	int mn,mx;
	struct node{
		int x,y,id,pos;
	};
	vector<node> V;
	vector<pair<int,int> > V1[N];
	struct Snode{
		int val,tag,lazy;
	}T[N<<2];
	#define val(x) T[(x)].val
	#define tag(x) T[(x)].tag
	#define lazy(x) T[(x)].lazy
	inline void pushdown(int p){
		if(!lazy(p))return;
		lazy(p)=0;
		lazy(p<<1)=1,lazy(p<<1|1)=1;
		tag(p<<1)=0,tag(p<<1|1)=0;
		val(p<<1)=0,val(p<<1|1)=0;
	}
	inline void pushup(int p){
		val(p)=max(val(p<<1),val(p<<1|1));
		val(p)+=tag(p);
	}
	void modify(int p,int l,int r,int ql,int qr,int v){
		if(ql<=l&&r<=qr){
			tag(p)+=v,val(p)+=v;
			return;
		}
		pushdown(p);
		int mid=l+r>>1;
		if(ql<=mid)modify(p<<1,l,mid,ql,qr,v);
		if(mid<qr)modify(p<<1|1,mid+1,r,ql,qr,v);
		pushup(p);
	}
	bool mark[N][4];
	inline int getpre(int x){
		int pre=0;
		int i=V[x].id;
		for(int j=V[x].pos-1;j>=0;j--)
			if(mark[i][j]){pre=V1[i][j].second;break;}
		return pre;
	}
	inline int getnxt(int x){
		int nxt=inf;
		int i=V[x].id;
		for(int j=V[x].pos+1;j<V1[i].size();j++)
			if(mark[i][j]){nxt=V1[i][j].second;break;}
		return nxt;
	}
	bool check(int mid,int X,int Y){
		V.clear();
		for(int i=1;i<=n;i++){
			V1[i].clear();
			for(int j=0;j<k;j++){
				int p1=j,p2=(j+1+X)%4;
				if(Y)swap(p1,p2);
				if(a[i][p1]>mn+mid||a[i][p2]<mx-mid)continue;
				V1[i].emplace_back(a[i][(j+2-X)%4],a[i][(j+3)%4]);
			}
			if(!V1[i].size())return 0;
			sort(V1[i].begin(),V1[i].end(),[](pair<int,int> &a,pair<int,int> &b){return a.second<b.second;});
			for(int j=0;j<V1[i].size();j++)
				V.push_back({V1[i][j].first,V1[i][j].second,i,j});
		}
		for(int i=1;i<=n;i++)
			for(int j=0;j<4;j++)
				mark[i][j]=0;
		sort(V.begin(),V.end(),[](node &a,node &b){return a.x<b.x;});
		lazy(1)=1,tag(1)=0,val(1)=0;
		for(int l=0,r=0;r<V.size();l++){
			for(;r<V.size()&&V[r].x<=V[l].x+mid;r++){
				mark[V[r].id][V[r].pos]=1;
				int pre=getpre(r),nxt=getnxt(r);
				int L=max(pre+1,V[r].y-mid),R=min(V[r].y,nxt-mid-1);
				if(L<=R)modify(1,1,mx,L,R,1);
			}
			if(val(1)==n)return 1;
			mark[V[l].id][V[l].pos]=0;
			int pre=getpre(l),nxt=getnxt(l);
			int L=max(pre+1,V[l].y-mid),R=min(V[l].y,nxt-mid-1);
			if(L<=R)modify(1,1,mx,L,R,-1);
		}
		return 0;
	}
	bool check1(int mid){
		if(check(mid,0,0))return 1;
		if(check(mid,0,1))return 1;
		return check(mid,1,1);
	}
	void main(){
		n=in();
		mn=inf,mx=0;
		for(int j=0;j<4;j++)
			for(int i=1;i<=n;i++){
				a[i][j]=in();
				mn=min(mn,a[i][j]),mx=max(mx,a[i][j]);
			}
		int l=0,r=mx-mn,mid;
		while(l<=r){
			mid=l+r>>1;
			if(check1(mid))r=mid-1;
			else l=mid+1;
		}
		printf("%d\n",r+1);
	}
}
int main(){
	freopen("lock.in","r",stdin);
	freopen("lock.out","w",stdout);
	int T=in();k=in();
	if(k==1)while(T--)solve1::main();
	if(k==2)while(T--)solve2::main();
	if(k==3)while(T--)solve3::main();
	if(k==4)while(T--)solve4::main();
	return 0;
}

标签:max,min,int,题解,ll,mid,春季,--,2023
From: https://www.cnblogs.com/william555/p/17183271.html

相关文章

  • [SDOI2019] 移动金币 题解
    首先考虑一个状态什么时候是合法的。不难把游戏过程抽象为阶梯Nim博弈。根据阶梯Nim博弈的结论,先手必胜当且仅当奇数位上的异或和不为0。考虑将本题中每个棋子后面......
  • C/C++课程设计题目[2023-03-06]
    C/C++课程设计题目[2023-03-06]课题1:公司考勤管理系统(一)、课程设计题目:某公司的考勤管理系统(二)、目的与要求:1、目的:(1)要求学生达到熟练掌握C++语言的基本知识和技能;(2......
  • AcWing 4490. 染色题解
    题目描述样例输入:612215211111输出3算法描述思路我们以样例为例讲讲思路。如何确保dfs能顺利便利呢,我们可以使用链式前向星来存图(树)C++代......
  • AcWing 4495. 数组操作题解
    思路此题较为简单,简述一下思路。从小到大排序,每次选取最小值,只要不为0即可每次都为序列减去一个数字太慢,但每个数又减去的数字一样,所以可以用minus记录每个数要减去的数......
  • 【2023-03-03】连岳摘抄
    23:59世上大部分的重大事情,都是由那些在似乎一点希望也没有时,仍然继续努力的人们所完成的。                        ......
  • 2023/03/03(五)晴,牛肉牛肉
    一天无事,晚上赶到家7点多,闷上米饭,带大宝跟我去超市买好吃的。大宝看见肉就走不动道儿,我说这个是澳大利亚牛肉,还有亚美利加牛肉,都不好吃,咱买日本牛肉吃,比昨天吃的冻牛肉还......
  • 2023.3.6python笔记
    Python3基本数据类型|菜鸟教程(runoob.com)了解到python基本数据类型string(字符串),tuple(元组),number(数字)   #数值不可改变list(列表),dictionary(字典),set(集合)......
  • 2023/3/5 周报
    周报本周总结​ 这周主要刷了ATC/CF,VP了几场,刷题数量较少。刚开学事情比较多。有在学前端等工程方面的内容。主题​ 无题目数量​ 20......
  • day05 (2023.3.5)
    1.条件判断,if单分支结构。 2.条件判断,ifelse双分支结构 3.ifelseifelse多分支 4.switch多分支结构  5.while循环 6.for循环 7.dowhile循环 ......
  • 2023.3.5周报
    本周总结:补充了一下自己图论中薄弱的一个部分,刷了些洛谷蓝色以上的题目。大方向:图论小专题:lca、树的直径等树上问题题目完成情况:20 ......