Loading

noip模拟59

A. 柱状图

很容易发现如果确定某个点一定是屋顶的话,那么答案是随 ta 的高度成单谷变化的.

所以可以选择枚举每个点,然后树状数组\(+\)三分.

但是我们发现对于这种曲线直接退火就可以,准确率很高,跑得也很快.

另外还可以线段树\(+\)二分,发现屋顶是一个 △,于是可以选择二分上面下面有多少个点.

A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll long long 
	#define ull unsigned ll
	#define lf long double
	#define lbt(x) (x&(-x))
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound
	#define ub upper_bound
	#define Fill(x,y) memset(x,y,sizeof x)
	#define Copy(x,y) memcpy(x,y,sizeof x)
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	inline ll read() {
		ll res=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0; 
		while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
		return cit?res:-res;
	}
} using namespace BSS;

const ll N=1e5+21;
const long long int inf=1e15;

ll m,n,cntx,cnty,ans,maxh,maxn;
ll h[N],wx[N],wy[N],lshx[N],lshy[N];
struct Bit_Array{
	ll res; ll c[N<<3];
	inline void update(ll x,ll w){
		for(;x<=maxn;x+=lbt(x)) c[x]+=w;
	}
	inline ll query(ll x){
		res=0; for(;x;x&=x-1) res+=c[x]; return res;
	}
}A,B,C,D;
inline ll calc(ll x,ll t){
	if(t-x+1<=0 or t-n+x<=0) return inf;
	ll res=0,tmp;
	tmp=ub(lshx+1,lshx+1+cntx,t-x)-lshx-1;
	res+=A.query(tmp)*(t-x)-B.query(tmp);
	res+=B.query(n)-B.query(tmp)-(A.query(n)-A.query(tmp))*(t-x);
	tmp=ub(lshy+1,lshy+1+cnty,t+x)-lshy-1;
	res+=C.query(tmp)*(t+x)-D.query(tmp);
	res+=D.query(n)-D.query(tmp)-(C.query(n)-C.query(tmp))*(t+x);
	// cout<<x<<" "<<t<<' '<<res<<endl;
	return res+abs(t-h[x]);
}
inline ll solve(ll x){
	ll l=1,r=maxh+n,lmid,rmid,vall,valr,res=inf;
	while(l<=r){
		rmid=(l+r)>>1,lmid=rmid-1;
		if(lmid<=l or rmid>=r) break;
		vall=calc(x,lmid),valr=calc(x,rmid);
		vall<valr ? r=rmid : l=lmid ;
	}
	for(int i=l;i<=r;i++) res=min(res,calc(x,i));
	return res;
}
signed main(){
	File(c);
	n=read(),ans=inf;
	for(int i=1;i<=n;i++) maxh=max(maxh,h[i]=read());
	for(int i=1;i<=n;i++){
		lshx[i]=wx[i]=h[i]-i,lshy[i]=wy[i]=h[i]+i;
	}
	sort(lshx+1,lshx+1+n),cntx=unique(lshx+1,lshx+1+n)-lshx-1;
	sort(lshy+1,lshy+1+n),cnty=unique(lshy+1,lshy+1+n)-lshy-1;
	maxn=max(cntx,cnty)+n;
	for(int i=n;i>=1;i--){
		wx[i]=lb(lshx+1,lshx+1+cntx,wx[i])-lshx;
		wy[i]=lb(lshy+1,lshy+1+cnty,wy[i])-lshy;
		C.update(wy[i],1),D.update(wy[i],h[i]+i);
	}
	for(int i=1;i<=n;i++){
		C.update(wy[i],-1),D.update(wy[i],-h[i]-i);
		// cout<<calc(i,1000)<<endl;
		ans=min(ans,solve(i));
		A.update(wx[i],1),B.update(wx[i],h[i]-i);
	}
	printf("%lld\n",ans),exit(0);
}

B. 应急棍

找规律,高精小数没有写.

B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll long long
	#define ull unsigned ll
	#define lf double
	#define lbt(x) (x&(-x))
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound 
	#define ub upper_bound
	#define Fill(x,y) memset(x,y,sizeof x)
	#define Copy(x,y) memcpy(x,y,sizeof x)
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	inline ll read() {
		ll w=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0; 
		while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
		return cit?w:-w;
	}
} using namespace BSS;

ll m,n,C;
ll pow2[40],pow4[40];
auto Work=[]()->void{
	ll op=read(); lf x,y;
	if(op==1) x=0,y=0; if(op==2) x=n,y=n;
	if(op==3) x=0,y=n; if(op==4) x=n,y=0;
	if(op<=4) return printf("%.10lf %.10lf\n",x,y),void();
	ll now=0; op-=4;
	while(op>pow4[now]+2*pow2[now]*(pow2[now]+1)) op-=pow4[now]+2*pow2[now]*(pow2[now]+1),now++;
	lf len=n/((lf)pow2[now]);
	if(op<=pow4[now]) x=len/2.0+(op-1)/pow2[now]*len,y=len/2.0+(op-1)%pow2[now]*len;
	else{
		op-=pow4[now],x=(op-1)/(pow2[now+1]+1)*len;
		if((op-1)%(pow2[now+1]+1)>=pow2[now]) x+=len/2.0,y=((op-1)%(pow2[now+1]+1)-pow2[now])*len;
		else y=(op-1)%(pow2[now+1]+1)*len+len/2.0;
	}
	printf("%.10lf %.10lf\n",x,y);
};
signed main(){
	File(a);
	pow2[0]=1,pow4[0]=1;
	for(ll i=1;i<=35;i++) pow2[i]=pow2[i-1]<<1ll,pow4[i]=pow4[i-1]<<2ll;
	C=read(); int Ts=read(); n=read();
	while(Ts--) Work();
	exit(0);
}

C. 擒敌拳

考场上测试点分治切了,单调队列 \(+\) 斜率优化.

每次枚举队列里的所有元素就行了.

正解是李超线段树.

C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll long long int
	#define ull unsigned ll
	#define lf double
	#define lbt(x) (x&(-x))
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound 
	#define ub upper_bound
	#define Fill(x,y) memset(x,y,sizeof x)
	#define Copy(x,y) memcpy(x,y,sizeof x)
	#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
	#define FILE(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	inline ll read() {
		int ss=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0; 
		while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
		return cit?ss:-ss;
	}
} using namespace BSS;

const ll N=2e5+21;

namespace DEQUE{
	struct Deque{
		ll l,r; ll q[N<<2];
		inline bool empty(){ return l>r; }
		inline ll size(){ return r-l+1; }
		inline ll front(){ return q[l]; }
		inline ll back(){ return q[r]; }
		inline void pop_front(){ l++; }
		inline void pop_back(){ r--; }
		inline void push_front(ll x){ q[--l]=x; }
		inline void push_back(ll x){ q[++r]=x; }
	} que;
} using namespace DEQUE;

ll m,n,maxh,ans,flag;
ll H[N];
struct I { ll h,id,lc; } p[N];
inline void Work1(){
	ll now;
	for(int i=1;i<=n;i++){
		maxh=max(maxh,p[i].h),p[i].lc=i;
		if(que.empty()) que.push_back(i),ans=max(ans,p[i].h);
		else{
			if(p[que.back()].h<p[i].h) que.push_back(i);
			else{
				while(que.size() and p[que.back()].h>=p[i].h){
					now=que.back(),que.pop_back();
					p[i].lc=min(p[now].lc,p[i].lc);
				}
				que.push_back(i);
			}
			for(int j=que.l;j<=que.r;j++){
				ans=max(ans,(i-p[que.q[j]].lc+1)*p[que.q[j]].h);
			}
		}
		printf("%lld ",max(ans,maxh));
	}	
}
inline ll caly(ll x){ return x*H[x]-H[x]; }
inline lf getxl(ll a,ll b){ return 1.0*(caly(a)-caly(b))/(H[a]-H[b]); }
inline void Work2(){
	for(int i=1;i<=n;i++) H[i]=p[i].h;
	que.push_back(1); ll res=0; printf("%lld ",H[1]);
	for(int i=2;i<=n;i++){
		while(que.l<que.r and getxl(que.q[que.l+1],que.front())<=i) que.pop_front();
		res=max(H[i],H[que.front()]*i-caly(que.front()));
		while(que.l<que.r and getxl(i,que.back())<=getxl(que.back(),que.q[que.r-1])) que.pop_back();
		que.push_back(i);
		printf("%lld ",res);
	}
}
signed main(){
	FILE(b);
	n=read(),que.l=n+1,que.r=n;flag=1;
	for(int i=1;i<=n;i++) p[i].h=read(),flag&=(p[i].h>=p[i-1].h);
	if(flag) Work2();
	else Work1();
	
	exit(0);
}

D. 边数

容易发现是一个基环内向树.

基环树上不断环选择倍增是一个很套路的想法.

于是就完了.

D_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
	// #define int long long
	#define lf long double
	#define pb push_back
	#define mp make_pair
	#define lb lower_bound
	#define ub upper_bound
	#define lbt(x) ((x)&(-(x)))
	#define Fill(x,y) memset(x,y,sizeof(x))
	#define Copy(x,y) memcpy(x,y,sizeof(x))
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	auto read=[]()->int{
		int w=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
		while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
		return cit?w:(-w);
	};
} using namespace BSS;

const int N=5e5+21,inf=0x3f3f3f3f;

int m,n,ts,ans,cnt,lg2;
int d[N],to[N],cir[N],vis[N],dep[N],nxt[N],rk[N<<1];
int dp[N][20];
vector<int> vec[N];
queue<int> que;
auto Put=[]()->void{
	for(int i=1;i<=n;i++) cout<<vis[i]<<' ';
	puts("");
};
auto SpCalc=[](int x)->bool{
	for(auto i : vec[x]) if(!vis[i]) return 1;
	return 0;
};
auto solve=[](int a)->int{
	int nx=vec[a].size(),ny=nx<<1,x,y,z=inf;
	for(int i=1;i<=nx;i++) rk[i]=vec[a][i-1],rk[i+nx]=rk[i];
	for(int i=1,j=1;i<=ny;i++,j=max(i,j)){
		while(vis[rk[j]]) j++; 
		nxt[i]=j; Fill(dp[i],0);
	}
	for(int i=1;i<=ny;i++) dp[i][0]=nxt[nxt[i]+m];
	for(int j=1;j<=lg2;j++){
		for(int i=1;i<=ny;i++)
			dp[i][j]=dp[dp[i][j-1]][j-1];
	}
	// nxt 表示该连哪一个了.
	// dp[i][j] 表示从 i 这个点开始连,连 2^j 边,下一个应该够哪里.
	// for(int j=1;j<=lg2;j++){
	// 	for(int i=1;i<=ny;i++) cout<<dp[i][j]<<' ';
	// 	puts("");
	// }
	for(int i=1;i<=nx;i++){
		x=i,y=0;
		for(int j=lg2;~j;j--)
			if(dp[x][j] and dp[x][j]<=i+nx) y|=1<<j,x=dp[x][j];
		y+=(x<i+nx),z=min(z,y);
	}
	return z;
};
auto Tope=[]()->void{
	int u,v; dep[1]=0,dep[to[1]]=1;
	for(int i=2;i<=n;i++) if(!d[i]) dep[i]=1,ans++;
	for(int i=2;i<=n;i++) if(dep[i]==1) que.push(i);
	while(que.size()){
		u=que.front(),que.pop(),v=to[u];
		if(dep[u]>m) dep[u]=1,ans++;
		dep[v]=min(dep[u]+1,dep[v]);
		if(!(--d[v])) que.push(v);
	}
};
auto Bfs=[]()->void{
	int u,v; vis[1]=1; assert(que.empty());
	for(int i=2;i<=n;i++) if(dep[i]==1) que.push(i);
	while(que.size()){
		u=que.front(),que.pop(),v=to[u],vis[u]=1;
		if(vis[v]) continue; 
		que.push(v),dep[v]=min(dep[v],dep[u]+1);
	}
};
signed main(){
	File(d);  
	n=read(),m=read(),lg2=log2(n)+1; int u,v;
	for(int i=1;i<=n;i++){
		u=read(),to[u]=read(),d[to[u]]++;
	}
	for(int i=1;i<=n;i++){
		if(vis[i]) continue; 
		u=i; 
		while(!vis[u]) vis[u]=i,u=to[u];
		if(vis[u]!=i) continue;
		v=u,u=to[u],cir[v]=++cnt,vec[cnt].pb(v);
		while(u!=v) cir[u]=cnt,vec[cnt].pb(u),u=to[u];
	}
	Fill(vis,0),Fill(dep,0x3f); Tope(),Bfs();
	for(int i=1;i<=n;i++) if(dep[i]>m) vis[i]=0;
	for(int i=1;i<=cnt;i++){
		if((int)vec[i].size()<m) { ans+=SpCalc(i); continue; }
		if(!SpCalc(i)) continue; 
		ans+=solve(i);
	}
	printf("%d",ans),exit(0);
}
posted @ 2021-09-23 21:26  AaMuXiiiiii  阅读(58)  评论(0编辑  收藏  举报