Loading

noip模拟35

A. 玩游戏

可以简单地把这个序列拆成一个 \(2\) ~ \(k\) 的序列\(A\)\(k+1\) ~ \(n\) 的序列\(B\).
发现只从\(A\)\(B\)的开头进行贪心的想法是显然错误的,于是考虑如何改进.
发现当序列\(A\)向前移动时,如果移动之后总和大于 \(0\) ,那么可以选择将\(B\)移动到开头到目前位置的最小值.
因为不会写\(O(nlogn)\),所以糊了一个\(O(n\)~\(n^2)\)的做法,这个复杂度和值域有关,如果卡的很紧的话是可以卡成\(n^2\)的.

A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define ll long long int
	#define ull unsigned ll
	#define re register ll 
	#define lf double
	#define lb lower_bound 
	#define ub upper_bound 
	#define mp make_pair
	#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
	#define Fill(x,y) memset(x,y,sizeof x)
	#define Copy(x,y) memcpy(x,y,sizeof x)
	inline ll read()
	{
		ll 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=1e5+21;

ll m,n,Ts;
ll a[N],b[N];
inline void Pre(){
	ll t=read(),s=read(); n=0,m=0; read();
	for(re i=2;i<=s;i++) a[s-i+1]=read();
	for(re i=2;i<=s;i++) n++,a[n]+=a[n-1];
	for(re i=s+1;i<=t;i++) m++,b[m]=b[m-1]+read();
}
inline void Work(){
	ll i=0,j=0;
	while(i<n){
		while(j<m and a[i]+b[j+1]<=0) j++;
		i++;
		while(j>0 and a[i]+b[j]>0) j--;
		if(a[i]+b[j]>0) { puts("No"); return ; }
	}
	while(j<m and a[i]+b[j+1]<=0) j++;
	if(i<n or j<m) puts("No");
	else puts("Yes");
}
signed main(){
	Ts=read();
	while(Ts--){
		Pre(),Work();
	}
	exit(0);
}

B. 排列

这种题目给的信息很少,那么一定就是推理性质了.
一个美妙的\(dp\)定义,\(f_{i,j,0/1}\)表示长度为\(i\)的序列,至多需要\(j\)次完成消除的方案,其中\(0/1\)表示边界有没有挨着更大值.
这里的\(0/1\)可以通俗地理解为:如果是\(0\),那么就是边界挨着更小值或者边界没有挨着值;反之则为\(1\).
于是\(dp\)转移就可以很显然地出现了.
\(f_{i,j,0}=\Sigma C^{k−1}_{i−1}∗f_{k−1,j−1,1}∗f_{i−k,j,0}\)
\(f_{i,j,1}=\Sigma C^{k−1}_{i−1}∗(f_{k−1,j,1}∗f_{i−k,j−1,1}+f_{k−1,j−1,1}∗f_{i−k,j,1}−f_{k−1,j−1,1}∗f_{i−k,j−1,1})\)
统计答案时差分一下就出来了.
\(ans=\Sigma C^{i−1}_{n−1}∗(f_{i−1,k,0}∗f_{n−i,k,0}−f_{i−1,k−1,0}∗f_{n−i,k−1,0})\)

B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define ll long long int
	#define lf double
	#define re register ll 
	#define ull unsigned ll
	#define mp make_pair
	#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)
	inline ll read()
	{
		ll 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=1e3+21;

ll n,m,mod,ans;
ll C[N][N];
ll f[N][N][2];
signed main(){
	n=read(),m=read(),mod=read(),C[0][0]=1;
	for(re i=1;i<=n;i++){
		C[0][i]=1;
		for(re j=1;j<=i;j++) C[j][i]=(C[j][i-1]+C[j-1][i-1])%mod;
	}
	if(m-1>=ceil(log2(n))) puts("0"),exit(0);
	for(re i=0;i<=m;i++) f[0][i][0]=1,f[0][i][1]=1;
	for(re i=1;i<=n;i++)
		for(re j=1;j<=m;j++)
			for(re k=1;k<=i;k++){
				(f[i][j][0]+=C[k-1][i-1]*f[k-1][j-1][1]%mod*f[i-k][j][0]%mod)%=mod,
				(f[i][j][1]+=C[k-1][i-1]*((f[k-1][j][1]*f[i-k][j-1][1]%mod+f[k-1][j-1][1]*f[i-k][j][1]%mod-f[k-1][j-1][1]*f[i-k][j-1][1]%mod+mod)%mod)%mod)%=mod;
			}
	for(re i=1;i<=n;i++) (ans+=C[i-1][n-1]*((f[i-1][m][0]*f[n-i][m][0]%mod-f[i-1][m-1][0]*f[n-i][m-1][0]%mod+mod)%mod)%mod)%=mod;
	printf("%lld\n",ans);
	exit(0);
}

C. 最短路

思路来自 \(Yubai\) .
发现需要从 \(1\) 走到 \(n\) ,再从 \(n\) 走到 \(1\) .
由于原图是有向边,所以可以把题目中给出的边看成正边,把正边的 \(u\)\(v\) 倒过来看成反边.
于是可以把原题转换成从 \(1\) 走到 \(n\),需要一次只经过正边的路径和一次只经过反边的路径.
\(dis_{i,j}\) 表示走正边走到 \(i\),再走反边走到 \(j\).
然后跑一个二维最短路就可以了.

C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define ll long long int
	#define lf double
	#define re register ll 
	#define ull unsigned ll
	#define mp make_pair
	#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)
	inline ll read()
	{
		ll 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=257,M=257*257;
ll m,n,lmt;
ll fee[N];
ll dis[N][N],vis[N][N];
struct Graph{
	ll ts; ll head[N];
	struct I { ll u,v,nxt; } e[M];
	inline void add(ll u,ll v){
		e[++ts].u=u,e[ts].v=v,e[ts].nxt=head[u],
		head[u]=ts;
	}
}A,B;
struct II {
	ll u,v,w;
	bool operator <(const II &i)const{
		return i.w<w;
	}
};
priority_queue<II> que;
bitset<N> bit[N][N];
inline void Dijk(){
	Fill(dis,0x3f); ll u,v,w,temp;
	dis[1][1]=fee[1],que.push(II{1,1,fee[1]});
	while(que.size()){
		u=que.top().u,v=que.top().v,w=que.top().w,que.pop();
		if(vis[u][v]) continue; vis[u][v]=1;
		for(re i=A.head[u];i;i=A.e[i].nxt){
			(temp=0)+=fee[A.e[i].v]*(!bit[u][v][A.e[i].v]);
			if(dis[A.e[i].v][v]>dis[u][v]+temp){
				bit[A.e[i].v][v]=bit[u][v],bit[A.e[i].v][v][A.e[i].v]=1;
				dis[A.e[i].v][v]=dis[u][v]+temp;
				que.push(II{A.e[i].v,v,dis[A.e[i].v][v]});
			}
		}
		for(re i=B.head[v];i;i=B.e[i].nxt){
			(temp=0)+=fee[B.e[i].v]*(!bit[u][v][B.e[i].v]);
			if(dis[u][B.e[i].v]>dis[u][v]+temp){
				bit[u][B.e[i].v]=bit[u][v],bit[u][B.e[i].v][B.e[i].v]=1;
				dis[u][B.e[i].v]=dis[u][v]+temp;
				que.push(II{u,B.e[i].v,dis[u][B.e[i].v]});
			}
		}
	}
}
signed main(){
	n=read(),m=read(); ll u,v;
	for(re i=1;i<=n;i++) fee[i]=read();
	for(re i=1;i<=m;i++) u=read(),v=read(),A.add(u,v),B.add(v,u);
	Dijk();
	if(dis[n][n]>=0x3f3f3f3f) puts("-1"),exit(0);
	printf("%lld\n",dis[n][n]);
	exit(0);
}

D. 矩形

发现很多矩形由于被包含,所以是无用的.
在没有思路的时候,或许删减一下是一个挺有效的策略,比如曾经做过的一道题目 \(z\).
关于如何删减,可以发现是一个显然的三维偏序.
然后考虑删减完之后应该怎么做,手玩几个样例,发现所有位于同一联通块的矩形有两条边是交叉形成 '十' 字的.
于是线段树维护即可.

D_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll 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) 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;		

ll m,n,cnt,tot,ans;
ll lsh[N<<2],vis[N];
multiset<pair<ll,ll> > s[N<<2];
struct I { ll x0,y0,x2,y2,die; } p[N];
vector<I> vec;
inline bool cmp1(I i,I j){
	if(i.x0!=j.x0) return i.x0<j.x0;
	if(i.y0!=j.y0) return i.y0<j.y0;
	if(i.x2!=j.x2) return i.x2>j.x2;
	return i.y2>j.y2;
}
inline bool cmp2(I i,I j){
	if(i.y0!=j.y0) return i.y0<j.y0;
	if(i.x2!=j.x2) return i.x2>j.x2;
	return i.y2>j.y2;
}
struct Bit_Array{
	ll res; ll c[N<<2];
	inline void update(ll x,ll w){
		for(;x>0;x&=(x-1)) c[x]=max(c[x],w);
	}
	inline void del(ll x){
		for(;x>0;x&=(x-1)) c[x]=0;
	}
	inline ll query(ll x){
		res=0; for(;x<=cnt;x+=lbt(x)) res=max(c[x],res); return res;
	}
} bit;
void cdq(ll l,ll r){
	if(l==r) return ;
//	if(l==1 and r==n) { for(int i=1;i<=n;i++) cout<<p[i].x0<<' '<<p[i].y0<<" "<<p[i].x2<<' '<<p[i].y2<<endl; puts(""); }
	ll mid=(l+r)>>1; cdq(l,mid),cdq(mid+1,r);
	sort(p+l,p+mid+1,cmp2),sort(p+mid+1,p+r+1,cmp2);
	ll p1=l,p2=mid+1,res;
//	cout<<"L:"<<l<<" R:"<<r<<endl;
	while(p1<=mid and p2<=r){
		if(p[p1].y0<=p[p2].y0){ bit.update(p[p1].x2,p[p1].y2),p1++; }
		else{ res=bit.query(p[p2].x2),p[p2].die|=(res>=p[p2].y2),p2++; }
	}
	while(p2<=r) res=bit.query(p[p2].x2),p[p2].die|=(res>=p[p2].y2),p2++; 
	for(int i=l;i<=p1;i++) bit.del(p[i].x2);
}
struct Segment{
	#define ls (x<<1)
	#define rs (x<<1|1)

	multiset<pair<ll,ll> > tr[N<<2];
	void update(ll x,ll l,ll r,ll ql,ll qr,pair<ll,ll> w){
		if(l>=ql and r<=qr) return tr[x].insert(w),void();
		ll mid=(l+r)>>1;
		if(ql<=mid) update(ls,l,mid,ql,qr,w);
		if(qr>mid) update(rs,mid+1,r,ql,qr,w);
	}
	ll query(ll x,ll l,ll r,ll pos,pair<ll,ll> w){
		if(tr[x].size()){
			auto it=tr[x].lb(mp(w.first,0));
			if(it!=tr[x].end() and it->first<=w.second){
				ll res=it->second; tr[x].erase(it);
				return res;
			}
		}
		if(l==r) return -1; ll mid=(l+r)>>1;
		return pos<=mid ? query(ls,l,mid,pos,w) : query(rs,mid+1,r,pos,w);
	}
	#undef ls 
	#undef rs
}X,Y;
void dfs(ll i){
	if(vis[i]) return ; vis[i]=1; ll v;
	while((v=X.query(1,1,cnt,p[i].x0,mp(p[i].y0,p[i].y2)))!=-1) dfs(v);
	while((v=X.query(1,1,cnt,p[i].x2,mp(p[i].y0,p[i].y2)))!=-1) dfs(v);
	while((v=Y.query(1,1,cnt,p[i].y0,mp(p[i].x0,p[i].x2)))!=-1) dfs(v);
	while((v=Y.query(1,1,cnt,p[i].y2,mp(p[i].x0,p[i].x2)))!=-1) dfs(v);
}
signed main(){
	n=read();
	for(int i=1;i<=n;i++){
		lsh[++cnt]=p[i].x0=read(),lsh[++cnt]=p[i].y0=read(),
		lsh[++cnt]=p[i].x2=read(),lsh[++cnt]=p[i].y2=read();
	}
	sort(lsh+1,lsh+1+cnt),cnt=unique(lsh+1,lsh+1+cnt)-lsh-1;
	for(int i=1;i<=n;i++){
		p[i].x0=lb(lsh+1,lsh+1+cnt,p[i].x0)-lsh,p[i].y0=lb(lsh+1,lsh+1+cnt,p[i].y0)-lsh;
		p[i].x2=lb(lsh+1,lsh+1+cnt,p[i].x2)-lsh,p[i].y2=lb(lsh+1,lsh+1+cnt,p[i].y2)-lsh;
	}
	sort(p+1,p+1+n,cmp1),cdq(1,n); 
	for(int i=1;i<=n;i++) if(!p[i].die) vec.push_back(p[i]);
	n=0; for(auto i : vec) p[++n]=i;
	for(int i=1;i<=n;i++){
		X.update(1,1,cnt,p[i].x0,p[i].x2,mp(p[i].y0,i));
		X.update(1,1,cnt,p[i].x0,p[i].x2,mp(p[i].y2,i));
		Y.update(1,1,cnt,p[i].y0,p[i].y2,mp(p[i].x0,i));
		Y.update(1,1,cnt,p[i].y0,p[i].y2,mp(p[i].x2,i));
	}
	for(int i=1;i<=n;i++){
		if(!vis[i]) ans++,dfs(i);
	}
	printf("%d\n",ans),exit(0);
}
posted @ 2021-08-14 20:32  AaMuXiiiiii  阅读(55)  评论(0编辑  收藏  举报