Loading

noip模拟33

A.Hunter

看到数据范围,想到要么\(O(n)\),要么\(O(nlogn)\)..
想着搞一搞数据结构,却丝毫没有考虑到期望的线性性质..
考虑每个猎人对第一个猎人的贡献,发现两者之间的死亡顺序的期望可以轻松求出。于是将期望累加得到答案..

A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll long long int 
	#define ull unsigend ll
	#define re register ll 
	#define lf double
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound 
	#define ub upper_bound
	#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) memset(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=1e6+55;
const ll mod=998244353;
ll n,m,sum;
ll w[N];
inline ll ksm(ll a,ll b,ll c){
	a%=c; ll temp=1;
	while(b){
		if(b&1) temp=(temp*a)%c;
		a=(a*a)%c; b>>=1;
	}
	return temp%c;
}	
signed main(){
	n=read(); ll temp;
	for(re i=1;i<=n;i++) w[i]=read();
	for(re i=2;i<=n;i++){
		temp=w[i]*ksm(w[1]+w[i],mod-2,mod)%mod;
		sum=(sum+temp)%mod;
	}
	++sum;
	printf("%lld",sum%mod);
	return 0;
}

B.Defence

裸的线段树合并,认真审题即可..

B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll long long int 
	#define ull unsigend ll
	#define re register ll 
	#define lf double
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound 
	#define ub upper_bound
	#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) memset(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+50;
ll m,n,q,ts,tot,flag;
ll head[N],rt[N*64],ls[N*64],rs[N*64],sum[N*64],lc[N*64],rc[N*64],len[N*64],ans[N];
struct I { ll u,v,nxt; } e[N<<1];

inline void add(ll u,ll v){
	e[++ts].u=u;
	e[ts].v=v;
	e[ts].nxt=head[u];
	head[u]=ts;
}
inline void pushup(ll x,ll l,ll r){
	sum[x]=sum[ls[x]]+sum[rs[x]];
	ll mid=(l+r)>>1,llen=mid-l+1,rlen=r-mid;
/*	if(x==rt[3]) {cout<<"Three\n";
	cout<<"sum:"<<sum[ls[x]]<<" "<<sum[rs[x]]<<'\n';
	cout<<l<<" "<<r<<" "<<lc[ls[x]]<<" "<<rc[ls[x]]<<" "<<lc[rs[x]]<<" "<<rc[rs[x]]<<endl;
	cout<<"L R:"<<llen<<" "<<rlen<<'\n';}
*/	if((!sum[ls[x]]) and (!sum[rs[x]])){
		len[x]=r-l+1;
		lc[x]=0; rc[x]=0;
	} else
	if(!sum[ls[x]]){
		len[x]=max(lc[rs[x]]-mid-1+llen,len[rs[x]]);
		lc[x]=lc[rs[x]]; rc[x]=rc[rs[x]];
	} else
	if(!sum[rs[x]]){
		len[x]=max(mid-rc[ls[x]]+rlen,len[ls[x]]);
		lc[x]=lc[ls[x]]; rc[x]=rc[ls[x]];
	} else
	if(sum[ls[x]] and sum[rs[x]]){
		len[x]=max(len[ls[x]],len[rs[x]]);
		len[x]=max(len[x],lc[rs[x]]-rc[ls[x]]-1);
		lc[x]=lc[ls[x]]; rc[x]=rc[rs[x]];
	}
//	if(rt[3]==x) cout<<"len:"<<len[x]<<endl<<endl;
	return ;
}
void merge(ll &x,ll y,ll l,ll r){
	if(!x) { x=y; return ; }
	if(!y) return ;
	if(l==r){
		sum[x]=sum[x]|sum[y];
		if(sum[x]){
			lc[x]=l;
			rc[x]=l;
			len[x]=0;
		}
		else{
			lc[x]=0;
			rc[x]=0;
			len[x]=1;
		}
		return ;
	}
	ll mid=(l+r)>>1;
	merge(ls[x],ls[y],l,mid);
	merge(rs[x],rs[y],mid+1,r);
	pushup(x,l,r);
	return ;
}
void update(ll &x,ll l,ll r,ll pos){
	if(!x) x=++tot;
	if(l==r){
		sum[x]=1; len[x]=0;
		lc[x]=l,rc[x]=l;
		return ;
	}
	ll mid=(l+r)>>1;
	if(pos<=mid) update(ls[x],l,mid,pos);
	else update(rs[x],mid+1,r,pos);
	pushup(x,l,r);
	return ;
}
void dfs(ll now,ll dad){
	if(flag) return ;
	for(re i=head[now];i;i=e[i].nxt){
		if(e[i].v==dad) continue;
		dfs(e[i].v,now);
		if(flag) return ;
		merge(rt[now],rt[e[i].v],1,m);
	}
//	if(now==3) cout<<lc[rt[now]]<<" skr "<<rc[rt[now]]<<" "<<len[rt[now]]<<endl;
	ll temp=lc[rt[now]]-1+m-rc[rt[now]];
	ans[now]=max(0*1ll,len[rt[now]]-temp)+temp;
	return ;
}
signed main(){
	n=read(); m=read(); q=read();
	ll u,v,w;
	for(re i=2;i<=n;i++){
		u=read(); v=read();
		add(u,v); add(v,u);
	}
	for(re i=1;i<=q;i++){
		u=read();
		update(rt[u],1,m,read());
	}
	dfs(1,0);
	for(re i=1;i<=n;i++){
		if(!rt[i]) puts("-1");
		else printf("%lld\n",ans[i]);
	}
	return 0;
}

C.Connect

直接想到了最大生成树,设\(path(1,n)\)为主路径,那么在最大生成树的基础上,在非主路径上各种连边即可..
但是这个东西应该是可以被轻松\(Hack\)的,这类题应该多去画图,自己多去手模几组样例,并及时进行对拍..
正解是在链的基础上进行两种操作:
<1> 将链的长度增加\(1\)
<2> 在链的某个节点\(x\)上连一坨点..且保证这些点只和\(x\)联通..
然后状压转移即可.

C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll long long int 
	#define ull unsigend ll
	#define re register ll 
	#define lf double
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound 
	#define ub upper_bound
	#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) memset(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=19;
ll n,m,sum,U;
ll d[N][N],f[1<<N][N];
ll dp[1<<N][N];
signed main(){
	n=read(); m=read();
	ll u,v,temp=0; U=(1<<n)-1;
	for(re i=1;i<=m;i++){
		u=read(); v=read();
		d[u][v]=d[v][u]=read();
		sum+=d[u][v];
	}
	for(re i=1;i<=U;i++){
		temp=0;
		for(re j=1;j<=n;j++){
			if((i>>(j-1))&1)
				for(re k=j+1;k<=n;k++)
					if((i>>(k-1))&1) temp+=d[j][k];
		}
		for(re j=1;j<=n;j++){
			f[i][j]=temp;
			if(!((i>>(j-1))&1)){
				for(re k=1;k<=n;k++)
					if((i>>(k-1))&1) f[i][j]+=d[k][j];
			}
		}
	}
	ll S,res=0;
	for(re i=1;i<=U;i++){
		if(!(i&1)) continue;
		for(re j=1;j<=n;j++){
			if((i>>(j-1))&1){
				for(re k=1;k<=n;k++){
					if((i>>(k-1))&1) continue;
					dp[i|(1<<(k-1))][k]=max(dp[i|(1<<(k-1))][k],dp[i][j]+d[j][k]);
				}
				S=U xor i;
				for(re T=S;T;T=(T-1)&S){
					for(re k=1;k<=n;k++){
						if((i>>(k-1))&1){
							dp[i|T][j]=max(dp[i|T][j],dp[i][j]+f[T][k]);
						}
					}
				}
			}
		}
	}
	printf("%lld",sum-dp[U][n]);
	return 0;
}
posted @ 2021-08-09 20:13  AaMuXiiiiii  阅读(35)  评论(0编辑  收藏  举报