省选模拟12

昨晚被zxb打呼噜吵到两点还没睡着,于是考试想补觉

但是没有睡着,于是只好去想题,于是一分钟打了第一题\(\mathcal{O(n^3)}\)的暴力

后来发现可以斜率优化到\(\mathcal{O(n^2)}\),写完之后想写递增的部分分可是不会

要是有了部分分的话就是正解了...

第二题是个交互,于是也只有暴力分,没想到二分,也没想到可以利用交集

第三题打了个最暴力的状压就走了

T1 数列array

发现每一段的最后一个一定是这一段的最大值,不然的话完全可以拆出来造成新的贡献

于是暴力的二维dp就可以变成一维的了,于是再次斜率优化,变成\(\mathcal{O(nlogn)}\)

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pa pair<int,int>
#define mk(x,y) make_pair(x,y)
#define fi first
#define se second
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
	int s=0,t=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s*t;
}
const int N=1e6+5;
int n,a[N],c,ans;
int dp[N];
struct XDS{
	#define ls x<<1
	#define rs x<<1|1
	int k[N*4],b[N*4];
	XDS(){fo(i,1,4e6)b[i]=-1e18;}
	int v(int k,int b,int x){return k*x+b;}
	void ins(int x,int l,int r,int qk,int qb){
		if(v(qk,qb,l)>=v(k[x],b[x],l)&&v(qk,qb,r)>=v(k[x],b[x],r))return k[x]=qk,b[x]=qb,void();
		if(v(qk,qb,l)<=v(k[x],b[x],l)&&v(qk,qb,r)<=v(k[x],b[x],r))return void();
		int mid=l+r>>1;
		if(v(qk,qb,mid)>v(k[x],b[x],mid))swap(k[x],qk),swap(b[x],qb);
		if(v(qk,qb,l)>v(k[x],b[x],l))ins(ls,l,mid,qk,qb);
		if(v(qk,qb,r)>v(k[x],b[x],r))ins(rs,mid+1,r,qk,qb);
		return ;
	}
	int query(int x,int l,int r,int pos){
		int ret=v(k[x],b[x],pos);
		if(l==r)return ret;
		int mid=l+r>>1;
		if(pos<=mid)ret=max(ret,query(ls,l,mid,pos));
		else ret=max(ret,query(rs,mid+1,r,pos));
		return ret;
	}
	#undef ls
	#undef rs
}xds;
signed main(){
	freopen("array.in","r",stdin);
	freopen("array.out","w",stdout);
	n=read();c=read();
	fo(i,1,n)a[i]=read();
	fo(i,1,n){
		if(i!=1)dp[i]=xds.query(1,1,1000000,a[i])+a[i]*a[i];
		xds.ins(1,1,1000000,-2*a[i],dp[i]+a[i]*a[i]+c);
	}
	printf("%lld",dp[n]);
	return 0;
}

T2 差异difference

可以二分找到最大值或者最小值的可能位置

具体来说,询问二会有一个最大差值,就是最大值和最小值的差值,于是我们二分位置

不断询问,我们可以找到同时包含最大最小值的最小前缀,那么最后一个数要么是最大值要么是最小值

我们利用这个最值去查找和其它数的差值

用二进制拆分,对于每一位未为1的做一个集合

一次询问这个集合,再一次询问集合和最值

这样就可以找到每个数和最值的差值

由于每个数都不一样,每个差值只会出现一次

我们取这个数为一的位的集合的交集,就是这个数的差值

这样的话,判断一下最值是最大值还是最小值,然后输出就好了

AC_code
#include<bits/stdc++.h>
#include "difference.h"
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=255;
vector<int> ans;int a[N];
int maxn,vis[1<<9];
vector<int> vec[1<<9],cha[1<<9];
map<int,int> mp;
bool check(int mid){
	vector<int> tmp,res;tmp.clear();
	fo(i,1,mid)tmp.push_back(i-1);
	res=qry2(tmp);int mx=0;
	for(auto i:res)mx=max(mx,i);
	return mx==maxn;
}
void find(int n,int m1,int m2){
	vector<int> tmp,res;tmp.clear();
	fo(i,1,n)tmp.push_back(i-1);
	res=qry2(tmp);
	for(auto i:res)maxn=max(maxn,i);
	int l=1,r=n,mid;
	while(l<r){
		mid=l+r>>1;
		if(check(mid))r=mid;
		else l=mid+1;
	}
	a[l]=qry1(l-1);
	fo(i,1,n){
		if(i==l)continue;
		int now=i;
		while(now){
			vec[now&-now].push_back(i-1);
			now-=now&-now;	
		}
	}
	fo(i,0,8){
		mp.clear();
		vec[1<<i].push_back(l-1);
		res=qry2(vec[1<<i]);
		for(auto x:res)mp[x]++;
		vec[1<<i].pop_back();
		res=qry2(vec[1<<i]);
		for(auto x:res){
			mp[x]--;
			if(mp[x]==0)mp.erase(x);
		}
		for(auto x:mp)cha[1<<i].push_back(x.first);
	}
	fo(i,1,n){
		if(i==l)continue;
		mp.clear();fo(j,0,8)vis[1<<j]=false;
		int now=i,sum=0;
		while(now){
			for(auto x:cha[now&-now])mp[x]++;
			vis[now&-now]=true;
			now-=now&-now;sum++;
		}
		fo(j,0,8)if(!vis[1<<j])for(auto x:cha[1<<j])mp[x]--;
		for(auto x:mp)if(x.second==sum)a[i]=x.first;
	}
	int mxc=0,id;
	fo(i,1,n)if(i!=l&&mxc<a[i])mxc=a[i],id=i;
	a[id]=qry1(id-1);
	if(a[id]<a[l]){
		fo(i,1,n)if(i!=id&&i!=l)a[i]=a[l]-a[i];
	}
	else fo(i,1,n)if(i!=id&&i!=l)a[i]=a[l]+a[i];
	fo(i,1,n)ans.push_back(a[i]);
	answer(ans);
}

T3 异或randomxor

不会呢

posted @ 2022-02-09 09:43  fengwu2005  阅读(64)  评论(1编辑  收藏  举报