• 9.26CSPS模拟12


    T1 开挂

    比较水的贪心题,可以证明一定只包含不相交,拿个栈就很好做了。

    点击查看代码
    #include <bits/stdc++.h>
    typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
    #define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
    #define Rep(i,a,b) for(int i=a;i<=b;++i) 
    #define Dwn(i,a,b) for(int i=a;i>=b;--i)
    #define pii pair<int,int>
    #define mair make_pair
    #define fir first
    #define sec second
    using namespace std;
    
    const int maxn=1e6+10;
    
    int n,a[maxn],b[maxn];
    vector<int>ned,spt;
    
    void solve(){
    	cin>>n;Rep(i,1,n)cin>>a[i];Rep(i,1,n)cin>>b[i];
    	sort(a+1,a+n+1);
    	Rep(i,2,n){
    		if(a[i]==a[i-1]){
    			ned.push_back(a[i]);
    		}else {
    			for(int j=a[i-1]+1;j<a[i] && (!ned.empty());++j){
    				spt.push_back(j-ned.back());ned.pop_back();
    			}
    		}
    	}
    	int now=a[n]+1;
    	while(!ned.empty()){ spt.push_back(now-ned.back());ned.pop_back();++now; }
    	sort(b+1,b+n+1);
    	ull ans=0;
    	if(!spt.empty()){
    		sort(spt.begin(),spt.end());
    		int it=1;
    		Dwn(i,spt.size()-1,0){
    			ans+=1LL*b[it]*spt[i];
    			++it;
    		}
    	}
    	cout<<ans<<"\n";
    }
    
    int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }
    
    
    

    T2 叁仟柒佰万

    比较水的dp题,可以处理出最后一个段以i结尾时,前i个数分为若干段的方案数,显然是求出一个最大的左端点使得区间mex恰好达到要求,左端点之前的所有位置都可以转移过来,维护前缀和就行。

    点击查看代码
    #include <bits/stdc++.h>
    typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
    #define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
    #define Rep(i,a,b) for(int i=a;i<=b;++i) 
    #define Dwn(i,a,b) for(int i=a;i>=b;--i)
    #define pii pair<int,int>
    #define mair make_pair
    #define fir first
    #define sec second
    using namespace std;
    
    const int maxn=3.7e7+10,Mod=1e9+7;
    const ll B=262143;
    
    #define gc if(++ip==ie)fread(ip=buf,1,SZ,stdin)
    const int SZ=1<<21;char buf[SZ],*ie=buf+SZ,*ip=ie-1;
    inline int read(){ gc;while(*ip<'-')gc; bool f=*ip=='-';if(f)gc; int x=*ip&15;gc; while(*ip>'-'){x*=10;x+=*ip&15;gc;} return f ? -x : x; }
    
    int tex,n;
    int a[maxn];
    int Mex,vis[300000],AMex;
    int	f[maxn],L[maxn];
    
    void solve(){
    	n=read();
    	Mex=AMex=0;
    	if(n==37000000){
    		int x,y;x=read(),y=read();
    		a[1]=0;Rep(i,2,n)a[i]=(1LL*a[i-1]*x+y+i)&B;
    	}else Rep(i,1,n)a[i]=read();
    	Rep(i,1,n){ ++vis[a[i]]; while(vis[Mex])++Mex; }
    	Rep(i,1,n)vis[a[i]]=f[i]=0;
    	AMex=Mex,Mex=0;
    	int ED=0;
    	Dwn(i,n,1){
    		++vis[a[i]];
    		while(vis[Mex])++Mex;
    		if(Mex==AMex){ ED=i;break; }
    	}
    	Rep(i,ED,n)vis[a[i]]=0;Mex=0;
    	int l=1,ans=0;
    	f[0]=1;
    	for(int i=1;i<ED;++i){
    		++vis[a[i]];
    		while(vis[Mex])++Mex;
    		if(Mex==AMex){
    			while(l<i && (a[l]>Mex || (vis[a[l]]>1))){--vis[a[l]];++l;}
    			L[i]=l;
    		}else L[i]=-1;
    		if(L[i]!=-1){ f[i]=f[L[i]-1];ans=(ans+f[i])%Mod; }
    		f[i]=(f[i]+f[i-1])%Mod;
    	}
    	Rep(i,1,n)vis[a[i]]=0;
    	cout<<(ans+1)%Mod<<"\n";
    
    }
    
    int main (){ tex=read();while(tex--)solve();return 0; }
    
    

    T3 超级加倍

    用了笛卡尔树,建出笛卡尔树使得两点树上路径的最大/小值为笛卡尔树上两点的lca,于是在大根/小根笛卡尔树上同时互为祖先关系的点对就是要求的路径数量,求这样的点对就是将一棵树转为dfs序,然后搜另一棵树,用BIT维护当前点到根的路径上出现了哪些dfs序,然后在BIT上查原来有几个点在它子树内就行。

    点击查看代码
    #include <bits/stdc++.h>
    typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
    #define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
    #define Rep(i,a,b) for(int i=a;i<=b;++i) 
    #define Dwn(i,a,b) for(int i=a;i>=b;--i)
    #define pii pair<int,int>
    #define mair make_pair
    #define fir first
    #define sec second
    using namespace std;
    
    const int maxn=2e6+10;
    
    int n;
    ll ans;
    int a[maxn];
    
    struct BIT{
    	int c[maxn];
    	#define lowbit(x) (x&-x)
    	void Add(int x,int d){ for(;x<=n;x+=lowbit(x))c[x]+=d; }
    	int Query(int x){ 
    		int res=0;for(;x;x-=lowbit(x))res+=c[x];return res; 
    	}
    	int Range(int x,int y){ return Query(y)-Query(x-1); }
    }B;
    
    struct Graph{
    	struct eg{int from,to,next;}e[maxn*2];
    	int len,head[maxn];int f[maxn];int fa[maxn];bool vis[maxn];
    	void lqx(int from,int to)
    	{ e[++len].from=from,e[len].to=to,e[len].next=head[from],head[from]=len; }
    }G;
    struct CTT{
    	struct eg{int from,to,next;}e[maxn*2];
    	int f[maxn];
    	int Find(int x){return f[x]==x ? x : f[x]=Find(f[x]);}
    	void Init(){ Rep(i,1,n)f[i]=i; }
    	int len,head[maxn];
    	void lqx(int from,int to)
    	{ e[++len].from=from,e[len].to=to,e[len].next=head[from],head[from]=len; }
    	void Build1(){
    		Init();
    		Rep(u,1,n){
    			for(int i=G.head[u];i;i=G.e[i].next){
    				int v=G.e[i].to;
    				if(v<u){
    					if(Find(u)==Find(v))continue;
    					lqx(Find(u),Find(v));
    					f[Find(v)]=Find(u);
    				}
    			}
    		}
    	}
    	void Build2(){
    		Init();
    		Dwn(u,n,1){
    			for(int i=G.head[u];i;i=G.e[i].next){
    				int v=G.e[i].to;
    				if(v>u){
    					if(Find(u)==Find(v))continue;
    					lqx(Find(u),Find(v));
    					f[Find(v)]=Find(u);
    				}
    			}
    		}
    	}
    }T,E;
    
    int st[maxn],ed[maxn],Te;
    
    void Dfs1(int u){ 
    	st[u]=++Te;
    	for(int i=T.head[u];i;i=T.e[i].next){ int v=T.e[i].to; Dfs1(v); } ed[u]=Te; 
    }
    void Dfs2(int u){
    	ans+=B.Range(st[u],ed[u]);
    	B.Add(st[u],1);
    	for(int i=E.head[u];i;i=E.e[i].next){ int v=E.e[i].to; Dfs2(v); }
    	B.Add(st[u],-1);
    }
    
    void solve(){
    	cin>>n;int x;
    	Rep(i,1,n){ cin>>x;if(x)G.lqx(i,x),G.lqx(x,i); }
    	T.Build1(),E.Build2();
    	Dfs1(n),Dfs2(1);
    	cout<<ans<<"\n";
    }
    
    int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }
    
    
    

    T4 欢乐豆

    提取子图最短路。

    如果没有特殊边,那么显然每个源到的所有点最短路都是源的点权。所以当一个点没有被特殊边涉及时,直接如此求即可。对于被特殊边涉及的点,点数规模较小,他们通过特殊边相连构成若干联通块,对于每个块可以求出块内全源最短路,然后算总和。
    路径类型分为

    • 块内 \(\rightarrow\) 块内
    • 块内 \(\rightarrow\) 块外
    • 块内 \(\rightarrow\) 块外 \(\rightarrow\) 块内

    前两种就普通dij,用线段树模拟,第三种显然只能是在块内走一段,然后走到点权最小的一个块外点再走回来,算答案的时候特殊考虑一下就行

    点击查看代码
    #include <bits/stdc++.h>
    typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
    #define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
    #define Rep(i,a,b) for(int i=a;i<=(int)b;++i) 
    #define Dwn(i,a,b) for(int i=a;i>=(int)b;--i)
    #define pii pair<int,int>
    #define mair make_pair
    #define fir first
    #define sec second
    #define int ll
    using namespace std;
    
    const int maxn=1e5+10,INF=1e17+20051107;
    
    int n,m;
    ll ans;
    int a[maxn],id[maxn],ind;
    multiset<int>MS;
    vector<int>pts[maxn];
    vector<pii>vec[maxn];
    int ud[maxn],dis[maxn];
    
    struct UN{
    	int f[maxn],siz[maxn];
    	void Init(int n){ Rep(i,1,n)f[i]=i,siz[i]=1; }
    	int Find(int x){ return f[x]==x ? x : f[x]=Find(f[x]); }
    	void Merge(int x,int y){ x=Find(x),y=Find(y); if(x==y)return; f[y]=x,siz[x]+=siz[y]; }
    }S;
    
    struct Seg{
    	struct Tree{ int mini,pos,lazy,tag; }tr[maxn<<2];
    	void Pushup(int rt){
    		tr[rt].mini=min(tr[rt<<1].mini,tr[rt<<1|1].mini);
    		if(tr[rt].mini==tr[rt<<1].mini &&(!tr[rt<<1].tag))tr[rt].pos=tr[rt<<1].pos;
    		else tr[rt].pos=tr[rt<<1|1].pos;
    		tr[rt].tag=tr[rt<<1].tag&tr[rt<<1|1].tag;
    	}
    	void Build(int rt,int l,int r){
    		tr[rt].mini=tr[rt].lazy=INF;tr[rt].tag=0,tr[rt].pos=l;
    		if(l==r)return;
    		int mid=(l+r)>>1;
    		Build(rt<<1,l,mid),Build(rt<<1|1,mid+1,r);
    	}
    	void Update(int rt,int w){tr[rt].mini=min(tr[rt].mini,w),tr[rt].lazy=min(tr[rt].lazy,w);}
    	void Pushdown(int rt){
    		if(tr[rt].lazy==INF)return;
    		if(!tr[rt<<1].tag)Update(rt<<1,tr[rt].lazy);
    		if(!tr[rt<<1|1].tag)Update(rt<<1|1,tr[rt].lazy);
    		tr[rt].lazy=INF;
    	}
    	void Delete(int rt,int l,int r,int x){
    		if(l==r)return tr[rt].mini=INF,tr[rt].tag=1,void();
    		int mid=(l+r)>>1;Pushdown(rt);
    		if(x<=mid)Delete(rt<<1,l,mid,x);
    		else Delete(rt<<1|1,mid+1,r,x);
    		Pushup(rt);
    	}
    	void Modify(int rt,int l,int r,int s,int t,int w){
    		if(tr[rt].tag || t<s)return;
    		if(s<=l && t>=r)return Update(rt,w);
    		int mid=(l+r)>>1;Pushdown(rt);
    		if(s<=mid)Modify(rt<<1,l,mid,s,t,w);
    		if(t>mid)Modify(rt<<1|1,mid+1,r,s,t,w);
    		Pushup(rt);
    	}
    }T;
    
    void Dij(int i,int u){
    	T.Build(1,1,pts[i].size());
    	T.Modify(1,1,pts[i].size(),ud[u],ud[u],0);
    	dis[ud[u]]=0;
    	while(T.tr[1].mini!=INF){
    		int x=T.tr[1].pos,dd=T.tr[1].mini,last=1;
    		dis[x]=dd;T.Delete(1,1,pts[i].size(),x);
    		x=pts[i][x-1];
    		for(auto it : vec[x]){
    			T.Modify(1,1,pts[i].size(),last,ud[it.fir]-1,a[x]+dd);
    			T.Modify(1,1,pts[i].size(),ud[it.fir],ud[it.fir],dd+it.sec);
    			last=ud[it.fir]+1;
    		}
    		T.Modify(1,1,pts[i].size(),last,pts[i].size(),dd+a[x]);
    	}
    }
    
    void solve(){
    	cin>>n>>m;Rep(i,1,n)cin>>a[i],MS.insert(a[i]);
    	int x,y,w;S.Init(n);
    	Rep(i,1,m){ cin>>x>>y>>w;vec[x].emplace_back(y,w);S.Merge(x,y); }
    	Rep(i,1,n){
    		sort(vec[i].begin(),vec[i].end());
    		if(S.Find(i)==i && S.siz[i]>1)id[i]=++ind;
    	}
    	Rep(i,1,n){
    		if(S.siz[S.Find(i)]>1)pts[id[S.Find(i)]].push_back(i);
    		else ans+=(n-1)*a[i];
    	}
    	Rep(i,1,ind){
    		for(int j=0;j<(int)pts[i].size();++j){ ud[pts[i][j]]=j+1;MS.erase(MS.find(a[pts[i][j]])); }
    		int tmp= MS.empty() ? INF : (*MS.begin());
    		for(auto u : pts[i]){
    			Dij(i,u);
    			int mini=INF;
    			Rep(j,1,pts[i].size())mini=min(mini,dis[j]+a[pts[i][j-1]]);
    			Rep(j,1,pts[i].size())ans+=min(dis[j],mini+tmp);
    			ans+=mini*(n-pts[i].size());
    		}
    		for(auto u : pts[i])MS.insert(a[u]);
    	}
    	cout<<ans<<"\n";
    }
    
    #undef int
    int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }
    
    
  • 相关阅读:
    HDU 4350 Card
    HDU 4287 Intelligent IME
    POJ Stars
    字符串处理
    NYOJ 63 小猴子下落
    在 DataGrid 控件中显示 SQL Server 数据库中的数据
    Linq to sql学习之查询句法
    SqlMethods
    SQLSERVER 2008 R2中的全文检索
    分享学习网站大全
  • 原文地址:https://www.cnblogs.com/Delov/p/16731982.html
Copyright © 2020-2023  润新知