【省選模擬】20/05/05 APIO2015

AA

  • 按位貪心有 n3logAn^3\log Adpdp
    n2000n\le 2000subtasksubtask 沒有下界,於是令 dpidp_i 表示到 ii,合法的最小段數
#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int N = 2e3 + 50;
typedef long long ll;
int n, A, B, a[N]; ll Sum;
namespace FSY{
	cs int N = 105;
	bool dp[N][N];
	bool chk(ll now, int t){
		memset(dp,0,sizeof(dp)); dp[0][0]=true;
		for(int i=1; i<=n; i++)
		for(int j=1; j<=i&&j<=B; j++)
		for(ll k=i,x=0; k; k--){
			x+=(ll)a[k]; 
			if((x & ((1ll<<t)+now-1)) != x) continue;
			dp[i][j]|=dp[k-1][j-1];
		} for(int i=A; i<=B; i++) if(dp[n][i]) return true;
		return false;
	}
	void work(){
		int k=0; while(Sum) Sum>>=1,++k; ll now=0;
		for(int i=k-1;~i;i--) if(!chk(now,i)) now|=1ll<<i;
		cout<<now; 
	}
}
namespace Yolanda{
	int dp[N];
	bool chk(ll now, int t){
		memset(dp,0x3f,sizeof(dp)); dp[0]=0;
		for(int i=1; i<=n; i++)
		for(ll j=i,x=0; j; j--){
			x+=(ll)a[j]; if((x & ((1ll<<t)+now-1)) != x) continue;
			dp[i]=min(dp[i],dp[j-1]+1); 
		} return dp[n]<=B;
	}
	void work(){
		int k=0; while(Sum) Sum>>=1,++k; ll now=0;
		for(int i=k-1;~i;i--) if(!chk(now,i)) now|=1ll<<i;
		cout<<now;
	}
}
int main(){
	#ifdef FSYolanda
	freopen("1.in","r",stdin);
	#endif
	scanf("%d%d%d",&n,&A,&B);
	for(int i=1; i<=n; i++) scanf("%d",&a[i]), Sum+=(ll)a[i];
	if(n<=100) return FSY::work(),0;
	else return Yolanda::work(),0;
} 

BB

  • 暴力建邊是 n2n^2,分析一下發現是 (n+m)n(n+m)\sqrt n 的,即長度 n\ge \sqrt n 的邊每次最多 n\sqrt n 條,本質不同的 <n<\sqrt n 的邊最多 nnn\sqrt n 條,每個點可以新轉移的邊的長度是原本的集合和這步之前到達的長度的集合,集合的總大小和邊集大小是一樣的,用 bitsetbitsethashhash 判重 可以做到 O((n+m)n)O((n+m)\sqrt n)
#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
typedef pair<int, int> pi;
cs int N = 3e4 + 50;
int n, m, b[N], p[N], mx;
vector<int> G[N]; bitset<N> ok[N];
struct node{ int a, b, d; };
queue<node> q; bool vs[N];
void trans(int v, int dt, int d){ 
	if(!vs[v]){
		for(int t : G[v]) if(!ok[v][t])
		ok[v][t]=true, q.push({v,t,d}); vs[v]=true;
	} if(!ok[v][dt]) ok[v][dt]=true, q.push({v,dt,d});
}
int main(){
	#ifdef FSYolanda
	freopen("1.in","r",stdin);
	#endif
	scanf("%d%d",&n,&m); int S=0,T=0;
	for(int i=1; i<=m; i++){
		scanf("%d%d",&b[i],&p[i]);
		if(i==1) S=b[i]; if(i==2) T=b[i];
		G[b[i]].pb(p[i]); mx=max(mx,p[i]);
	} for(int t : G[S]) q.push({S,t,0}), ok[S][t]=true; vs[S]=true;
	while(!q.empty()){
		node x = q.front(); q.pop();
		int u=x.a, dt=x.b; if(u==T) return cout<<x.d,0;
		if(u-dt>=0) trans(u-dt,dt,x.d+1);
		if(u+dt<n) trans(u+dt,dt,x.d+1);
	} puts("-1"); return 0;
}

CC

  • 按中點排序,存在一個分解點左邊的走左邊的橋右邊的走右邊的橋,用數據結構維護中位數即可
#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
namespace IO{
	cs int Rlen=1<<22|1;
	inline char gc(){
		static char buf[Rlen],*p1,*p2;
		(p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin));
		return p1==p2?EOF:*p1++;
	}
	int read(){
		int x=0; char c=gc(); bool f=false;
		while(!isdigit(c)) f=c=='-', c=gc();
		while(isdigit(c)) x=(((x<<2)+x)<<1)+(c^48), c=gc();
		return f?-x:x; 
	} int op(){
		char c=gc(); while(isspace(c)) c=gc(); 
		return c=='A'?0:1;
	}
} using namespace IO;
typedef long long ll;
cs ll INF = 1e18;
cs int N = 1e5 + 50;
int K, n, S[N], T[N], bin[N<<1], sz; ll Ans;
namespace zkw{
	cs int M = 1<<18;
	int sz[M<<1]; ll sm[M<<1];
	void clr(){ memset(sz,0,sizeof(sz)); memset(sm,0,sizeof(sm)); }
	void add(int x, ll v){ for(x+=M;x;x>>=1) ++sz[x],sm[x]+=v; }
	ll query(){
		int k=sz[1]>>1, x=1; ll as=0;
		while(true){
			if(x>M) break; if(k<=sz[x<<1]) x<<=1;
			else k-=sz[x<<1], x=x<<1|1;  
		} int v=bin[x-M]; for(;x;x>>=1){
			if(x&1) as+=(ll)sz[x^1]*v-sm[x^1];
			else as+=(ll)sm[x^1]-(ll)sz[x^1]*v;
		} return as;
	}
}
int main(){
	#ifdef FSYolanda
	freopen("1.in","r",stdin);
	#endif
	K=read(), n=read(); int m=0;
	for(int i=1,x,y; i<=n; i++){
		x=op(); S[i]=read(); y=op(); T[i]=read();
		if(x==y){ Ans+=(ll)abs(T[i]-S[i]); continue; }
		bin[++sz]=S[++m]=S[i], bin[++sz]=T[m]=T[i];
	} sort(bin+1,bin+sz+1); n=m;
	int x=bin[(sz+1)>>1]; ll mn=0;
	for(int i=1; i<=n; i++) mn+=(ll)abs(T[i]-x)+(ll)abs(S[i]-x);
	if(K==1) return cout<<Ans+mn+n,0;
	sz=unique(bin+1,bin+sz+1)-(bin+1);
	static int id[N];
	for(int i=1; i<=n; i++) id[i]=i;
	sort(id+1,id+n+1,[](cs int &i, cs int &j){ 
		return S[i]+T[i] < S[j]+T[j];
	}); static ll pr[N], sf[N];
	for(int i=1,x,y,u; i<=n; i++){
		u=id[i];
		x=lower_bound(bin+1,bin+sz+1,S[u])-bin;
		y=lower_bound(bin+1,bin+sz+1,T[u])-bin;
		zkw::add(x,S[u]); zkw::add(y,T[u]); pr[i]=zkw::query();
	} zkw::clr();
	for(int i=n,x,y,u; i>=1; i--){
		u=id[i]; 
		x=lower_bound(bin+1,bin+sz+1,S[u])-bin;
		y=lower_bound(bin+1,bin+sz+1,T[u])-bin;
		zkw::add(x,S[u]); zkw::add(y,T[u]); 
		sf[i]=zkw::query(); mn=min(mn,pr[i]+sf[i+1]);
	} cout<<Ans+mn+n; return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章