1. 程式人生 > >noip 2018 模擬賽9

noip 2018 模擬賽9

T1T_1——policy(3115)

Description:

有一個nmn \cdot m的矩形,現在有qq次詢問,每次詢問一個aba \cdot b的子矩形,若它的最大值mx,權值和為sum,求min{mxabsum}min\{mx\cdot a\cdot b-sum\}n,m1000,Ai,j109,q10n,m\le1000,A_{i,j}\le10^9,q\le10

Solution:

  • 發現這個就是一個無腦的資料結構題
  • 複雜度實在太卡…那麼帶log\log的話很容易就掛
  • 所以就想到一些線性的做法,比如單調佇列
  • 這樣複雜度就是Θ(n2q)\Theta(n^2q)

Code:

#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define ll long long
template<class T>inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
template<class T>inline void Rd(T &x){
	x=0;char c;
	while((c=getchar())<48);
	do x=(x<<1)+(x<<3)+(c^48);
	while((c=getchar())>47);
}

const int N=1002;
#define INF 0x3f3f3f3f3f3f3f3fll

int n,m,q;
int a,b;
int A[N][N],B[N][N],Q[N];
ll sum[N][N];

void solve(){
	ll ans=INF;
	REP(i,1,n){
		int l=0,r=0;
		REP(j,1,m){
			while(l<r && Q[l]<=j-b) ++l;
			while(l<r && A[i][Q[r-1]]<A[i][j]) --r;
			Q[r++]=j;
			B[i][j]=A[i][Q[l]];
		}
	}
	
	REP(j,b,m){
		int l=0,r=0;
		REP(i,1,n){
			while(l<r && Q[l]<=i-a) ++l;
			while(l<r && B[Q[r-1]][j]<B[i][j]) --r;
			Q[r++]=i;
			if(a<=i){
				ll x=sum[i][j]-sum[i-a][j]-sum[i][j-b]+sum[i-a][j-b];
				ll y=1ll*B[Q[l]][j]*a*b;
				chkmin(ans,y-x);
			}
		}
	}
	printf("%lld\n",ans);
}

int main(){
//	freopen("policy.in","r",stdin);
//	freopen("policy.out","w",stdout);
	Rd(n),Rd(m);
	REP(i,1,n) REP(j,1,m)Rd(A[i][j]),sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+A[i][j];
	
	Rd(q);
	while(q--)Rd(a),Rd(b),solve();

	return 0;
}

T2T_2——ricehub(3074)

Description: 在一條xx軸上,有nn個米倉,每個米倉的的糧食都是11,且知道它們的位置pip_i,以及座標範圍LL。問在某個點建一個倉庫,在總花費不超過BB的情況下,求最大的倉庫糧食量,一糧食每一單位的運費為11n106,L109,B21015n\le10^6,L\le10^9,B\le2\cdot 10^{15}

Solution:

  • 首先有一個O(n3)O(n^3)的做法
  • 因為倉庫只對一個區間[l,r][l,r]的米倉有影響
  • 模擬資料發現,它對花費的最優貢獻一定是(
    prpl)+(pr1pl+1)...+(pmid+1pmid1)(p_r-p_l)+(p_{r-1}-p_{l+1})...+(p_{mid+1}-p_{mid-1})
  • 即倉庫要建在中位數時最優。
  • 那麼對於每個左端點ii,我們可以線性找到它的右端點jj,再利用字首和求一個最優花費是否超過BB即可。

Code:

#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define ll long long
template<class T>inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
template<class T>inline void Rd(T &x){
	x=0;char c;
	while((c=getchar())<48);
	do x=(x<<1)+(x<<3)+(c^48);
	while((c=getchar())>47);
}

const int N=1e5+2;

int n,L;
ll B;
int p[N];

struct p20{
	void solve(){
		int ans=0;
		REP(i,1,n) REP(j,i+1,n) {
			int l=i,r=j;
			ll sum=0;
			while(l<r) sum+=p[r]-p[l],l++,r--;
			if(sum<=B) chkmax(ans,j-i+1);
		}
		printf("%d\n",ans);
	}
}p1;

struct p100{
	ll sum[N];
	bool check(int l,int r){
		int mid=(l+r)>>1;
		ll cost=1ll*p[mid]*(mid-l+1)-(sum[mid]-sum[l-1])+sum[r]-sum[mid]-1ll*p[mid]*(r-mid);
		return cost<=B;
	}
	
	void solve(){
		REP(i,1,n) sum[i]=sum[i-1]+p[i];
		int j=1,ans=0;
		REP(i,1,n){
			while(j<=n && check(i,j)) ++j;
			chkmax(ans,j-i);
		}
		printf("%d\n",ans);		
	}
}p2;

int main(){
//	freopen("ricehub.in","r",stdin);
//	freopen("ricehub.out","w",stdout);
	Rd(n),Rd(L),Rd(B);
	REP(i,1,n) Rd(p[i]);
	
//	if(n<=100)p1.solve();//O(n^3)
//	else 
	p2.solve();
	
	return 0;
}

T3T_3——war(3117)

Description:

有一個nn個點,mm條邊的圖,每個點都有顏色,顏色種類的範圍為[1,K][1,K]。 現在有qq個操作,每個操作將點xx的顏色改為kk,在每個操作後求不同顏色的最小距離。 n2105,m4105,K106,q2105,wi106n\le2\cdot 10^5,m\le4\cdot 10^5,K\le10^6,q\le2\cdot 10^5,w_i\le10^6

Solution:

  • 待更新

Code