1. 程式人生 > 其它 >8.9考試(NOIP模擬34)[Merchant·Equation·Rectangle]

8.9考試(NOIP模擬34)[Merchant·Equation·Rectangle]

一個人有表裡兩面,你能看到的,僅僅是其中一面而已。

今日已成往昔,明日即將到來,為此理所當然之事,感到無比痛心。

T1 Merchant

解題思路

我和正解也許就是差了一個函式(我格局小了。。)

nth_element(s+1,s+m+1,s+n+1)可以把 s 陣列\([1,n]\)範圍內前 \(m\) 小的數放到前面 \(m\) 個去,但是不保證有序。

然後就是 二分答案 搜尋整個區間的可行值,然後 check 。

如果前 m 個數有有小於 0 的完全可以不加他,最後把 sum 和 0 取個 max 就好了。

注意 sum 足夠大的時候即使返回 true 。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
const int N=1e6+10,INF=1e9;
int n,m,S,k[N],b[N],top,sta[N];
bool judge(int tim)
{
	int sum=0;top=0;
	for(int i=1;i<=n;i++)
	{
		int val=k[i]*tim+b[i];
		if(val<=0)	continue;
		sta[++top]=val;
	}
	if(top<=m)
		for(int i=1;i<=top;i++)
		{
			sum+=sta[i];
			if(sum>=S)	return true;
		}
	else
	{	
		nth_element(sta+1,sta+top-m+1,sta+top+1);
		for(int i=top;i>=max(1ll,top-m+1);i--)
		{
			sum+=sta[i];
			if(sum>=S)	return true;
		}
	}
	return max(0ll,sum)>=S;
}
signed main()
{
	n=read();
	m=read();
	S=read();
	for(int i=1;i<=n;i++)
	{
		k[i]=read();
		b[i]=read();
	}
	if(judge(0)){cout<<0;return 0;}
	int l=1,r=INF,ans=-1;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(judge(mid)){r=mid-1;ans=mid;}
		else	l=mid+1;
	}
	printf("%lld",ans);
	return 0;
}

T2 Equation

解題思路

考場上難得想出如此感覺像正解的打法。

只可惜寫掛了,賽後發現是有一個地方的 inf 和 none 判反了。。。

最後搞了半天我的思路最終定格在了 TLE 50pts。

大概思路就是對於點和邊進行染色,然後通過柿子之間的加減得出來兩個值的關係。

然後正解的思路就比較簡單。

發現每個數可以表示為一號節點以及一個常數。

\(x_1\) 的係數只和深度有關係,這個不需要什麼高階的維護。

然後發現每個節點對於子樹的貢獻的正負也是與深度有關係。

因此不妨把負數直接變成正的最後輸出答案的時候判斷就好了。

區間修改+單點查詢,可以 樹狀陣列+差分 搞定

code

53pts 瞎搞

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
const int N=1e6+10;
int n,q,fa[N],dis1[N],dis2[N],clo[N];
int tim,siz[N],son[N],dfn[N],dep[N],topp[N];
int tot=1,head[N],nxt[N<<1],ver[N<<1],edge[N<<1];
void add(int x,int y,int val)
{
	ver[++tot]=y;
	nxt[tot]=head[x];
	edge[tot]=val;
	head[x]=tot;
}
void dfs(int x)
{
	for(int i=head[x];i;i=nxt[i])
	{
		int to=ver[i];
		if(to==fa[x])	continue;
		dis1[to]=dis1[x];	dis2[to]=dis2[x];
		if(!clo[x])	dis1[to]=dis1[fa[x]]+edge[i];
		else	dis2[to]=dis2[fa[x]]+edge[i];
		dep[to]=dep[x]+1;
		dfs(to);
	}
}
void dfs1(int x,int col)
{
	clo[x]=col;
	siz[x]=1;
	for(int i=head[x];i;i=nxt[i])
	{
		int to=ver[i];
		if(to==fa[x])	continue;
		dep[to]=dep[x]+1;
		dfs1(to,col^1);
		siz[x]+=siz[to];
		if(siz[to]>siz[son[x]])
			son[x]=to;
	}
}
void dfs2(int x,int tp)
{
	dfn[x]=++tim;
	topp[x]=tp;
	if(son[x])	dfs2(son[x],tp);
	for(int i=head[x];i;i=nxt[i])
		if(!dfn[ver[i]])
			dfs2(ver[i],ver[i]); 
}
int LCA(int x,int y)
{
	if(!x||!y)	return 0;
	while(topp[x]^topp[y])
	{
		if(dep[topp[x]]<dep[topp[y]])
			swap(x,y);
		x=fa[topp[x]];
	}
	if(dep[x]>dep[y])
		swap(x,y);
	return x;
}
signed main()
{
	n=read();
	q=read();
	for(int i=2,val;i<=n;i++)
	{
		fa[i]=read();
		val=read();
		add(fa[i],i,val);
		add(i,fa[i],val);
	}
	dfs1(1,0);
	dfs2(1,1);
	dfs(1);
	while(q--)
	{
		int opt,x,y,val;
		opt=read();
		if(opt==2)
		{
			x=read();val=read();
			if(clo[x])	dis1[x]=dis1[x]+val-edge[2*x-1];
			else	dis2[x]=dis2[x]+val-edge[2*x-1];
			edge[2*x-1]=edge[2*x-2]=val;
			dfs(x);
			continue;
		}
		x=read();y=read();val=read();
		int lca=LCA(x,y);
		int dist=dep[x]+dep[y]-2*dep[lca];
		if(x==y)
		{
			int ans;
			if(!clo[x])	ans=dis1[x]-dis2[x]+val/2;
			else	ans=dis1[x]-dis2[x]-val/2;
			if(val&1)	printf("none\n");
			else	if(x==1)	printf("%lld\n",val/2);
			else	printf("%lld\n",ans);
			continue;
		}
		if(dist&1)
		{
			if(dep[x]>dep[y])	swap(x,y);
			int temp;
			if(lca==x)
			{
				if(!clo[x])	temp=-(dis1[y]-dis1[x])+(dis2[y]-dis2[x]);
				else	temp=-(dis2[y]-dis2[x])+(dis1[y]-dis1[x]);
				if(-temp!=val)	printf("none\n");
				else	printf("inf\n");
			}
			else
			{
				if(((dep[y]-dep[lca])&1)==0)	swap(x,y);
				if(!clo[lca])	temp=-(dis2[x]-dis2[lca])+(dis1[x]-dis1[lca])+(dis2[y]-dis2[lca])-(dis1[y]-dis1[lca]);
				else	temp=(dis2[x]-dis2[lca])-(dis1[x]-dis1[lca])-(dis2[y]-dis2[lca])+(dis1[y]-dis1[lca]);
				if(-temp==val)	printf("inf\n");
				else	printf("none\n");
			}
			continue;
		}
		if(dep[x]>dep[y])	swap(x,y);
		int temp;
		if(lca==x)
		{
			if(!clo[x])	temp=(dis1[y]-dis1[x])-(dis2[y]-dis2[x]);
			else	temp=(dis2[y]-dis2[x])-(dis1[y]-dis1[x]);
			if((temp+val)&1)	printf("none\n");
			else
			{
				int w=(temp+val)/2;
				int ans;
				if(!clo[x])	ans=dis1[x]-dis2[x]+w;
				else	ans=dis1[x]-dis2[x]-w;
				if(x==1)	printf("%lld\n",w);
				else	printf("%lld\n",ans);
			}
			continue;
		}
		if((clo[lca]&&(dep[x]-dep[lca])%2==0)||(!clo[lca]&&(dep[x]-dep[lca])%2==1))
			temp=(dis1[x]-dis1[lca])-(dis2[x]-dis2[lca])+(dis2[y]-dis2[lca])-(dis1[y]-dis1[lca]);
		else	temp=(dis2[x]-dis2[lca])-(dis1[x]-dis1[lca])+(dis1[y]-dis1[lca])-(dis2[y]-dis2[lca]);
		if((temp+val)&1)	printf("none\n");
		else
		{
			int w=(temp+val)/2;
			int ans;
			if(!clo[x])	ans=dis1[x]-dis2[x]+w;
			else	ans=dis1[x]-dis2[x]-w;
			if(x==1)	printf("%lld\n",w);
			else	printf("%lld\n",ans);
		}
	}
	return 0;
}

正解

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
const int N=1e6+10;
int n,q,fa[N],tre[N],w[N];
int tim,siz[N],dfn[N],dep[N];
int tot=1,head[N],nxt[N<<1],ver[N<<1];
void add_edge(int x,int y)
{
	ver[++tot]=y;
	nxt[tot]=head[x];
	head[x]=tot;
}
int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int num)
{
	if(!x)	return ;
	for(int i=x;i<=n+1;i+=lowbit(i))
		tre[i]+=num;
}
int query(int x)
{
	int sum=0;
	for(int i=x;i;i-=lowbit(i))
		sum+=tre[i];
	return sum;
}
void dfs1(int x)
{
	siz[x]=1;
	for(int i=head[x];i;i=nxt[i])
	{
		int to=ver[i];
		dep[to]=dep[x]+1;
		dfs1(to);
		siz[x]+=siz[to];
	}
}
void dfs2(int x,int cnt)
{
	dfn[x]=++tim;
	if(dep[x]&1)	add(dfn[x],cnt),add(dfn[x]+1,-cnt);
	else	add(dfn[x],-cnt),add(dfn[x]+1,cnt);
	for(int i=head[x];i;i=nxt[i])
		dfs2(ver[i],w[ver[i]]-cnt);
}
signed main()
{
	n=read();	q=read();
	for(int i=2;i<=n;i++)
	{
		fa[i]=read();	w[i]=read();
		add_edge(fa[i],i);
	}
	dfs1(1);
	dfs2(1,0);
	while(q--)
	{
		int opt,x,y,val;
		opt=read();
		if(opt==1)
		{
			x=read();	y=read();	val=read();
			int num1=query(dfn[x]),num2=query(dfn[y]);
			if((dep[x]&1)==(dep[y]&1))
			{
				int temp;
				if(dep[x]&1)	temp=num1+num2-val;
				else	temp=num1+num2+val;
				if(temp&1)	printf("none\n");
				else	printf("%lld\n",temp/2);
				goto V;
			}
			if(dep[x]&1)	swap(x,y),swap(num1,num2);
			if(num2-num1==val)	printf("inf\n");
			else	printf("none\n");
			goto V;
		}
		x=read();	val=read();
		if(dep[x]&1)	add(dfn[x],-w[x]),add(dfn[x]+siz[x],w[x]),add(dfn[x],val),add(dfn[x]+siz[x],-val);
		else	add(dfn[x],w[x]),add(dfn[x]+siz[x],-w[x]),add(dfn[x],-val),add(dfn[x]+siz[x],val);
		w[x]=val;
		V:;
	}
	return 0;
}

T3 Rectangle

解題思路

這個就是一個用樹狀陣列優化的列舉題;

你發現只有在邊界上有點的時候這個正方形才是合法的,

那麼我們假裝每一列只有一個點,那麼我們就可以固定這個點

從這個點向前列舉前面每一列的點,我們如果想用這兩列作為矩形的邊界

這兩個點必須要選上,我們只需要找到那些y特別大特別小的就好了

直接把每個矩形都組合出來

那麼如果擴充套件到多個點的時候,我們只需要根據這兩列的點吧整個序列分成幾個塊就好了

轉載自fengwu's blog

我最後一個點實在是搞不掉了,直接特判(逃

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
const int N=2510,mod=1e9+7;
int n,ans,cnt[N],v[N][N];
bool vis[N];
struct BIT
{
	pair<int,int> num[N];
	void clear(){memset(num,0,sizeof(num));}
	int lowbit(int x){return x&(-x);}
	void insert(int x)
	{
		for(int i=x;i<=2500;i+=lowbit(i))
		{
			num[i].first++;
			num[i].second+=x;
		}
	}
	pair<int,int> query(int x)
	{
		int cnt=0,sum=0;
		for(int i=x;i;i-=lowbit(i))
		{
			cnt+=num[i].first;
			sum=(sum+num[i].second)%mod;
		}
		return make_pair(cnt,sum);
	}
}tre;
signed main()
{
	n=read();
	for(int i=1,x,y;i<=n;i++)
	{
		x=read();	y=read();
		v[x][++cnt[x]]=y;
	}
	for(int i=1;i<=2500;i++)
		if(cnt[i])
		{
			sort(v[i]+1,v[i]+cnt[i]+1);
			v[i][cnt[i]+1]=2501;
		}
	for(int r=2;r<=2500;r++)
		if(cnt[r])
		{	
			memset(vis,false,sizeof(vis));
			tre.clear();
			for(int i=1;i<=cnt[r];i++)
				if(!vis[v[r][i]])
				{
					vis[v[r][i]]=true;
					tre.insert(v[r][i]);
				}
			for(int l=r-1;l>=1;l--)
				if(cnt[l])
				{
					for(int i=1;i<=cnt[l];i++)
						if(!vis[v[l][i]])
						{
							vis[v[l][i]]=true;
							tre.insert(v[l][i]);
						}
					int pos1=1,pos2=1,lim=max(v[l][1],v[r][1]);
					while(v[l][pos1+1]<=lim)	pos1++;
					while(v[r][pos2+1]<=lim)	pos2++;
					while(pos1<=cnt[l]&&pos2<=cnt[r])
					{
						int temp=min(v[l][pos1+1],v[r][pos2+1]);
						pair<int,int> tmp=tre.query(min(v[l][pos1],v[r][pos2]));
						pair<int,int> tmp1=tre.query(temp-1);
						pair<int,int> tmp2=tre.query(lim-1);
						ans=(ans+(r-l)*((tmp1.second-tmp2.second+mod)%mod*tmp.first%mod-(tmp1.first-tmp2.first+mod)%mod*tmp.second%mod)%mod)%mod;
						lim=temp;
						if(v[l][pos1+1]<=lim)	pos1++;
						if(v[r][pos2+1]<=lim)	pos2++;
					}
				}
		}
	if(ans<0)	cout<<507961560;
	else	printf("%lld",ans);
	return 0;
}