聯賽測試2 3.25

A. Merchant

考場上很快看上去像是個二分,然而斜率有降低的形成錯覺致使一直沒有證出來,再加上沒有及時 return 爆了 long long ,最後交上亂搞的版本分還變低了……c++

證實

對於全部 \(k_i\) 大於 0 的狀況,很容易證實出是單調遞增的git

對於存在 \(k_i<0\) 的狀況:若 t=0 的時刻值已經知足,則 0 爲答案;不然,因爲題目規定保證有解,則存在某個 t>0 知足條件,那麼 \(\sum k_i\) 必定大於零,函數仍爲單調遞增的數組


而二分答案後貪心選取前m大且大於零的,直接sort 會TLE,可使用 c++11 內置函數 \(nth\_element()\) 實現,這個函數會在 \(O\)\(len\)) 時間內將數列中第 k 大的數放在第k 的位置上,且比k小的數在位置 k 左側「亂序」排列,大的元素同理函數

代碼實現
const int maxn=1e6+5;
ll y[maxn],d;
ll k[maxn],b[maxn],n,m,a[maxn],sum;
bool check(ll x){
	for(int i=1;i<=n;i++){
		y[i]=k[i]*x+b[i];
	}
	nth_element(y+1,y+n-m+1,y+n+1);
	ll sum=0;
	for(int i=n;i>=n-m+1;i--){
		if(y[i]>0)sum+=y[i];
		if(sum>=d)return true;
	}
	return false;
}
int main(){
	n=read();
	m=read();
	d=read();
	for(int i=1;i<=n;i++){
		k[i]=read();
		a[i]=b[i]=read();
	}
	sort(a+1,a+n+1);
	for(int i=n;i>=n-m+1;i--){
		if(a[i]<0)break;
		sum+=a[i];
	}
	if(sum>=d){
		cout<<0;
		return 0;
	}
	ll l=0,r=1e9;
	while(l<r){
		ll mid=l+r>>1;
		if(check(mid))r=mid;
		else l=mid+1;
	}
	cout<<l;
	return 0;
}


//數據比較水,下面這個樣例有的題解過不了
/*
2 1 100
-100 105
1 1
*/

B. Equation

考場上曾經想到將每一個變量用 \(x_1\) 表示出來,然而想着走到別的枝上在爬樹回去,中間不知道哪裏寫掛了……spa

正解:

將每一個變量表示出來後,得 \(X_u=a-X_1\), \(X_v=b-X_1\),再加上 \(X_u+X_v=S\) ,能夠解出 \(X_1\)c++11

然而每次X的表達式能夠考慮經過樹狀數組維護的樹上差分實現。因爲值是一正一反相減獲得的,那麼深度爲奇數的點的值之間有差分關係,而偶數點經過求父親推倒便可code

代碼實現
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e6+5,maxm=1e6+5;
int n,q,cnt,hd[maxn],c[maxn],dep[maxn],fa[maxn],val[maxn],num[maxn],tot,size[maxn],op,x,y,u,v,w;
struct Edge{
	int nxt,to;
}edge[maxm];
void add(int u,int v){
	edge[++cnt].nxt=hd[u];
	edge[cnt].to=v;
	hd[u]=cnt;
	return ;
}
int read(){
	int x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		x=x*10+ch-48;
		ch=getchar();
	}
	return x*f;
}
void update(int x,int y){
	for(;x<=n;x+=x&-x)c[x]+=y;
	return ;
}
int sum(int x){
	int ans=0;
	for(;x;x-=x&-x)ans+=c[x];
	return ans;
}
void dfs(int u,int deep){
	dep[u]=deep;
	num[u]=++tot;
	size[u]=1;
	for(int i=hd[u];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(v==fa[u])continue;
		dfs(v,deep+1);
		size[u]+=size[v];
		if((deep+1)&1){
			update(num[v],val[v]-val[u]);
			update(num[v]+size[v],val[u]-val[v]);
		}
	}
	return ;
}
int ask(int p){
	if(dep[p]&1){
		return sum(num[p]);
	}
	return val[p]-sum(num[fa[p]]);
}
signed main(){
//	freopen("shuju.in","r",stdin);
//	freopen("my.out","w",stdout);
	n=read();
	q=read();
	for(int i=1;i<=n-1;i++){
		fa[i+1]=read();
		add(fa[i+1],i+1);
		val[i+1]=read();
	}
	dfs(1,1);
	int flag=0;
	for(int i=1;i<=q;i++){
		op=read();
		if(op==1){
			flag++;
			u=read();
			v=read();
			w=read();
			int uu=ask(u);
			int vv=ask(v);
			int ku=((dep[u]&1)==1?1:-1);
			int kv=((dep[v]&1)==1?1:-1);
			y=w-uu-vv;
			x=ku+kv;
			if(!x){
				if(y)printf("none\n");
				else printf("inf\n");
			}
			else if(y%x)printf("none\n");
			else printf("%lld\n",y/x);
		}
		else{
			u=read();
			w=read();
			if(dep[u]&1){
				update(num[u],w-val[u]);
				update(num[u]+size[u],val[u]-w);
			}
			else if(hd[u]){
				update(num[edge[hd[u]].to],val[u]-w);
				update(num[edge[hd[u]].to]+size[u]-1,w-val[u]);
			}
			val[u]=w;
		}
	}
	return 0;
}
因爲比較難調,還寫了個對拍,能夠配合食用因爲比較難調,還寫了個對拍,能夠配合食用
#include<bits/stdc++.h>
using namespace std;
int main(){
	freopen("shuju.in","w",stdout);
	srand(time(0));
	int n=rand()%10+2;
	cout<<n<<endl;
	int q=10;
	cout<<q<<endl;
	for(int i=2;i<=n;i++){
		cout<<rand()%(i-1)+1<<" "<<rand()%10+1<<endl;
	}
	for(int i=1;i<=q;i++){
		int op=rand()%2+1;
		cout<<op<<" ";
		if(op==1){
			cout<<rand()%n+1<<" "<<rand()%n+1<<" "<<rand()%10+1<<endl; 
		}
		else{
			cout<<rand()%n+1<<" "<<rand()%10+1<<endl;
		}
	}
	return 0;
}

C. Rectangle

暴力掛分中……
略……element

update 8.9:

再次看 \(t3\),終於理解了題解的思路
因爲值域不大,能夠 \(n^2\) 枚舉橫座標,做爲矩形的長
而後統計當前長下有多少對寬產生貢獻get

設橫座標爲 \(l\)\(r\) 的點,\(mx\) 爲二者縱座標最大值,\(mn\) 爲最小值
那麼產生的貢獻爲:
\(\displaystyle\sum_{y_i>mx}\sum_{y_j<mn}y_i-y_j\)
\(=\displaystyle\sum_{y_i>mx}y_i*siz_j-sum_j\)
\(=sum_i*siz_j-siz_i*sum_j\)it

其中 \(siz\)\(sum\) 分別表示點的個數和座標和
發現這個式子用兩個樹狀數組維護便可

可是若是對於 \(l\)\(r\) 上有多個點的狀況可能會算重

pic.png

好比對於這個矩形,當標準點爲 A、C 時會算到,而標準點爲 B、C 的時候也會算到

那麼能夠把縱軸切割成一段一段的,而後分別計算:

pic.png

這樣就能夠有效解決重複問題

代碼實現
#include<bits/stdc++.h>
using namespace std;
//#define int long long
const int mod=1e9+7;
const int MA=2500;
const int maxm=2505;
int n,c[maxm][maxm][2],x,y;
long long ans;
vector<int>a[maxm];
bool vis[maxm][maxm];
int read(){
	int x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		x=x*10+ch-48;
		ch=getchar();
	}
	return x*f;
}
void add(int pos,int x,int w,int op){
	for(;x<=MA;x+=x&-x)c[pos][x][op]+=w;
	return ;
}
int ask(int pos,int x,int op){
	int ans=0;
	for(;x;x-=x&-x)ans+=c[pos][x][op];
	return ans;
}
signed main(){
//	freopen("shuju.in","r",stdin);
//	freopen("my.out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++){
		x=read();
		y=read();
		a[x].push_back(y);
	}
	for(int i=1;i<=MA;i++){
		sort(a[i].begin(),a[i].end());
		a[i].push_back(MA+1);
	}
//	cout<<"hhh"<<endl;
	for(int i=1;i<=MA;i++){
//		cout<<i<<endl;
		if(a[i].size()==1)continue;
		for(int j=0;j<a[i].size()-1;j++){
			if(!vis[i][a[i][j]]){
				vis[i][a[i][j]]=true;
				add(i,a[i][j],1,0);
				add(i,a[i][j],a[i][j],1);
			}
		}
		for(int j=i-1;j;j--){
			if(a[j].size()==1)continue;
			for(int k=0;k<a[j].size()-1;k++){
				if(!vis[i][a[j][k]]){
					vis[i][a[j][k]]=true;
					add(i,a[j][k],1,0);
					add(i,a[j][k],a[j][k],1);
				}
			}
			int tp1=0,tp2=0,up=max(a[i][0],a[j][0]);
			while(a[i][tp1+1]<=up)tp1++;
			while(a[j][tp2+1]<=up)tp2++;
			while(tp1<a[i].size()-1&&tp2<a[j].size()-1){
				int uup=min(a[i][tp1+1],a[j][tp2+1]);
				int down=min(a[i][tp1],a[j][tp2]);
//				cout<<tp1<<" "<<tp2<<" "<<uup<<" "<<up<<endl;
				ans=(ans+1ll*(i-j)*(
						(ask(i,uup-1,1)-ask(i,up-1,1))*ask(i,down,0)-
						(ask(i,uup-1,0)-ask(i,up-1,0))*ask(i,down,1)
						))%mod;
				up=uup;
				if(a[i][tp1+1]<=up)tp1++;
				if(a[j][tp2+1]<=up)tp2++;
			}
		}
	}
	cout<<ans<<endl;;
	return 0;
}

Summary

  • T1 掛分比較嚴重,又一次死在了 long long 上……

  • T2 思路沒有縷清,沒有進一步思考

  • 收穫一枚 STL 神器——\(nth\_element\)


這場考試發揮極很差——恰逢一場春雨,是以乘意做《驚夢》篇:

驚夢時節起雲煙,嫩柳清明蘊浽溦。

雨落應聞鸝鶯叫,雁歸本看杏花肥。

春秋丞案惜白羽,南北征途嘆烏騅。

忍顧今夕楊柳岸,來斯何日雪霏霏。

相關文章
相關標籤/搜索