省选模拟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
不会呢
QQ:2953174821