• 测试「2020牛客NOIP赛前集训营-提高组(第三场)总结」


    T1

    (A+B) 看作一个整体,记作 (T) 。则:

    第一种变化:

    [egin{aligned} T & o 2 imes T\ C & o C-T end{aligned} ]

    第二种变化:

    [egin{aligned} T & o T-C\ C & o 2 imes C end{aligned} ]

    发现 (T+C) 始终不变,令 (C+T=S) ,则 (T=S-C)

    发现第一种变化中 (C o C-T=C-(S-C)=2 imes C-S=2 imes C { m mod} S) ,第二种变化中 (C o 2 imes C=2 imes C { m mod} S)

    那么得出结论:(K) 轮变化后,(C o C imes 2^K { m mod} S) ,快速幂即可。

    ( ext{Code}:)

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef long long lxl;
    
    template <typename T>
    inline void read(T &x)
    {
    	x=0;T f=1;char ch=getchar();
    	while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	x*=f;
    }
    
    inline lxl fmi(lxl a,lxl b,lxl mod)
    {
    	lxl res=1;
    	a%=mod;
    	while(b>0)
    	{
    		if(b&1) (res*=a)%=mod;
    		(a*=a)%=mod;
    		b>>=1;
    	}
    	return res;
    }
    
    lxl A,B,C,K;
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("A.in","r",stdin);
    	freopen("A.out","w",stdout);
    #endif
    	int T;read(T);
    	while(T--)
    	{
    		read(A),read(B),read(C),read(K);
    		lxl mod=A+B+C;
    		printf("%lld
    ",C*fmi(2,K,mod)%mod);
    	}
    	return 0;
    }
    

    T2

    考虑从小到大加边,记录一个前缀和即可。注意判断一条边都不能走的情况的种类数是 (1)

    ( ext{Code}:)

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <bitset>
    #define Rint register int
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long lxl;
    const int maxn=5e5+5,maxc=605;
    int mod;
    
    template <typename T>
    inline void read(T &x)
    {
    	x=0;T f=1;char ch=getchar();
    	while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	x*=f;
    }
    
    struct edge
    {
    	int u,v;
    	lxl w;
    	edge(int u,int v,lxl w):u(u),v(v),w(w){}
    	edge(){}
    	inline bool operator < (const edge &T)const
    	{
    		return w<T.w;
    	}
    }e[maxn];
    
    int n,m,q,start,opt;
    int color[maxn];
    int fa[maxn];
    bitset<maxc> siz[maxn];
    lxl sum[maxn],f[maxn];
    
    inline int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
    
    inline bool merge(int u,int v)
    {
    	int x=find(u),y=find(v);
    	if(x==y) return false;
    	fa[x]=y;
    	siz[y]=siz[x]|siz[y];
    	return true;
    }
    
    inline lxl query(lxl x)
    {
    	int pos=upper_bound(e+1,e+m+1,edge(-1,-1,x))-e-1;
    	return sum[pos]+(x-e[pos].w+1)*f[pos];
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("B.in","r",stdin);
    	freopen("B.out","w",stdout);
    #endif
    	read(n),read(m),read(q),read(start),read(opt);
    	if(opt) read(mod);
    	for(int i=1;i<=n;++i) read(color[i]);
    	for(int i=1,u,v,w;i<=m;++i)
    	{
    		read(u),read(v),read(w);
    		e[i]=edge(u,v,w);
    	}
    	for(int i=1;i<=n;++i)
    	{
    		fa[i]=i;
    		siz[i].set(color[i]);
    	}
    	sort(e+1,e+m+1);
    	for(int i=1;i<=m;++i)
    	{
    		int u=e[i].u,v=e[i].v;
    		merge(u,v);
    		f[i]=siz[find(start)].count();
    	}
    	f[0]=1;
    	for(int i=1;i<=m;++i)
    		sum[i]=sum[i-1]+f[i-1]*(e[i].w-e[i-1].w);
    	int l,r;
    	lxl lastans=0;
    	while(q--)
    	{
    		read(l),read(r);
    		if(opt) l=(l^lastans)%mod+1,r=(r^lastans)%mod+1;
    		if(l>r) swap(l,r);
    		lastans=query(r)-query(l-1);
    		printf("%lld
    ",lastans);
    	}
    	return 0;
    }
    

    T3

    令某个进行过1操作的结点编号为 (i) ,操作的时刻为 (t_i) ,令询问的点为 (x) ,当前时刻为 (t_x) ,也就是说要求一个点 (i),满足:

    [dis(i,x)leq t_x-t_i ]

    (LCA(i,x)=y) 拆一下式子:

    [egin{aligned} dep_i+dep_x-2 imes dep_y&leq t_x-t_i\ t_i+dep_i-2 imes dep_y&leq t_x-dep_x end{aligned} ]

    这个式子的右边只和 (x) 有关,右边除了 (y) 只和 (i) 有关。尝试让左边也之和 (i) 有关。

    (f)(i)(x) 的某个公共祖先,显然,当 (f=LCA(i,x)) ,即 (dep_f) 取到最大值时,下面这个式子的左边取到最小值:

    [t_i+dep_i-2 imes dep_fleq t_x-dep_x ]

    于是可以用线段树+树链剖分维护链上 (t_i+dep_i) 的最小值,和 (dep_f) 的最大值,进而得到区间内 (t_i+dep_i-2 imes dep_f) 的最小值。

    进行操作1时,更新 (x) 到根的路径上的 (t_i+dep_i)

    查询时,只需要查询 (x) 到根的路径上 (t_i+dep_i-2 imes dep_f) 的最小值,判断它与 (t_x-dep_x) 的大小关系即可。

    ( ext{Code}:)

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #define Rint register int
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long lxl;
    const int maxn=1e5+5;
    
    #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    char buf[1<<21],*p1=buf,*p2=buf;
    template <typename T>
    inline void read(T &x)
    {
    	x=0;T f=1;char ch=getchar();
    	while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	x*=f;
    }
    
    struct edge
    {
    	int u,v,next;
    	edge(int u,int v,int next):u(u),v(v),next(next){}
    	edge(){}
    }e[maxn<<1];
    
    int head[maxn],ecnt;
    
    inline void add(int u,int v)
    {
    	e[ecnt]=edge(u,v,head[u]);
    	head[u]=ecnt++;
    }
    
    int n,m;
    
    int dfn[maxn],idx[maxn],dep[maxn],dfs_cnt;
    int fa[maxn],top[maxn],son[maxn],siz[maxn];
    
    void dfs1(int u)
    {
    	dep[u]=dep[fa[u]]+1;
    	siz[u]=1;
    	for(int i=head[u];~i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(v==fa[u]) continue;
    		fa[v]=u;
    		dfs1(v);
    		siz[u]+=siz[v];
    		if(siz[son[u]]<siz[v]) son[u]=v;
    	}
    }
    
    void dfs2(int u,int t)
    {
    	dfn[u]=++dfs_cnt;
    	idx[dfn[u]]=u;
    	top[u]=t;
    	if(!son[u]) return;
    	dfs2(son[u],t);
    	for(int i=head[u];~i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(v==fa[u]||v==son[u]) continue;
    		dfs2(v,v);
    	}
    }
    
    namespace Segment_Tree
    {
    	struct node
    	{
    		int l,r;
    		int Maxdis,Ans,lazy;
    		bool clear;
    		node(int l,int r,int Maxdis=0,int Ans=INF,int lazy=INF,bool clear=false)
    			:l(l),r(r),Maxdis(Maxdis),Ans(Ans),lazy(lazy),clear(clear){}
    		node(){}
    	}tree[maxn<<2];
    	#define ls (p<<1)
    	#define rs (p<<1|1)
    	inline void clear(int p)
    	{
    		tree[p].Ans=tree[p].lazy=INF;
    		tree[p].clear=true;
    	}
    	inline void push_down(int p)
    	{
    		if(!tree[p].clear) return;
    		clear(ls);clear(rs);
    		tree[p].clear=false;
    	}
    	inline void update(int p)
    	{
    		tree[p].Ans=min(tree[p].lazy-tree[p].Maxdis,min(tree[ls].Ans,tree[rs].Ans));
    	}
    	void build(int p,int l,int r)
    	{
    		tree[p]=node(l,r);
    		if(l==r) return tree[p].Maxdis=2*dep[idx[l]],void();
    		int mid=(l+r)>>1;
    		build(ls,l,mid);
    		build(rs,mid+1,r);
    		tree[p].Maxdis=max(tree[ls].Maxdis,tree[rs].Maxdis);
    	}
    	inline void calcu(int p,int d)
    	{
    		tree[p].lazy=min(tree[p].lazy,d);
    		tree[p].Ans=min(tree[p].Ans,tree[p].lazy-tree[p].Maxdis);
    	}
    	void modify(int p,int L,int R,int d)
    	{
    		int l=tree[p].l,r=tree[p].r;
    		if(L<=l&&r<=R) return calcu(p,d),void();
    		push_down(p);
    		int mid=(l+r)>>1;
    		if(L<=mid) modify(ls,L,R,d);
    		if(R>mid) modify(rs,L,R,d);
    		update(p);
    	}
    	int query(int p,int L,int R,int val=INF)
    	{
    		int l=tree[p].l,r=tree[p].r;
    		if(L<=l&&r<=R) return min(tree[p].Ans,val-tree[p].Maxdis);
    		push_down(p);
    		int mid=(l+r)>>1,ans=INF;
    		if(L<=mid) ans=min(ans,query(ls,L,R,min(val,tree[p].lazy)));
    		if(R>mid) ans=min(ans,query(rs,L,R,min(val,tree[p].lazy)));
    		return ans;
    	}
    }
    
    inline void modify(int x,int d)
    {
    	for(;x;x=fa[top[x]])
    		Segment_Tree::modify(1,dfn[top[x]],dfn[x],d);
    }
    
    inline int query(int x)
    {
    	int res=INF;
    	for(;x;x=fa[top[x]])
    		res=min(res,Segment_Tree::query(1,dfn[top[x]],dfn[x]));
    	return res;
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("C.in","r",stdin);
    	freopen("C.out","w",stdout);
    #endif
    	read(n),read(m);
    	memset(head,-1,sizeof(head));
    	for(int i=1,u,v;i<n;++i)
    	{
    		read(u),read(v);
    		add(u,v);add(v,u);
    	}
    	dfs1(1);
    	dfs2(1,1);
    	Segment_Tree::build(1,1,n);
    	int opt,x;
    	for(int i=1;i<=m;++i)
    	{
    		read(opt),read(x);
    		if(opt==1) modify(x,i+dep[x]);
    		else if(opt==2) Segment_Tree::clear(1);
    		else puts(query(x)<=i-dep[x]?"wrxcsd":"orzFsYo");
    	}
    	return 0;
    }
    

    T4

    因为攻击力始终不变,所以每个魔物的攻击次数是固定的,记为 (H_i) ,将打败这个魔物获得的宝石数记为 (B_i) ,则打败这个魔物后,打之后的每个魔物 (j) 受到的伤害均会减少 (H_j imes B_i)

    考虑一个最优的打怪序列:({p_1,p_2,cdots,p_{n-1}}) 。若交换其中的 (p_i)(p_{i+1}) ,那么减少的总伤害将会变化 (H_i imes B_{i+1}-H_{i+1} imes B_i) ,因为交换前的序列一定更优,则有:

    [egin{aligned} H_i imes B_{i+1}-H_{i+1} imes B_ileq 0\ frac{B_i}{H_i}geq frac{B_{i+1}}{H_{i+1}} end{aligned} ]

    于是按照 (frac{B_i}{H_i}) 排序,依次打。

    若当前性价比最高的魔物还打不到,那么打完它的父亲后一定会立刻打它,于是在堆贪心时用并查集缩点即可。

    ( ext{Code}:)

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <vector>
    #define Rint register int
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long lxl;
    const int maxn=1e5+5;
    
    template <typename T>
    inline void read(T &x)
    {
    	x=0;T f=1;char ch=getchar();
    	while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	x*=f;
    }
    
    struct edge
    {
    	int u,v,next;
    	edge(int u,int v,int next):u(u),v(v),next(next){}
    	edge(){}
    }e[maxn<<1];
    
    int head[maxn],ecnt;
    
    inline void add(int u,int v)
    {
    	e[ecnt]=edge(u,v,head[u]);
    	head[u]=ecnt++;
    }
    
    namespace Union_Find
    {
    	int fa[maxn];
    	inline int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
    }
    
    int n;
    typedef pair<double,int> pii;
    priority_queue<pii> q;
    
    struct creature
    {
    	lxl lif,att,def;
    }cre[maxn];
    
    lxl lif,att,def;
    lxl H[maxn],B[maxn];
    lxl H1[maxn],B1[maxn];
    int fa[maxn];
    
    void dfs(int u)
    {
    	for(int i=head[u];~i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(v==fa[u]) continue;
    		fa[v]=u;
    		dfs(v);
    	}
    }
    
    bool tag[maxn],vis[maxn];
    vector<int> siz[maxn];
    
    void calcu(int u)
    {
    	tag[u]=true;
    	lif-=(cre[u].att-def)*H[u];
    	def+=B[u];
    	for(auto v:siz[u])
    		calcu(v);
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("D.in","r",stdin);
    #endif
    	read(n);
    	memset(head,-1,sizeof(head));
    	for(int i=1,u,v;i<n;++i)
    	{
    		read(u),read(v);
    		add(u,v);add(v,u);
    	}
    	dfs(1);
    	read(lif),read(att),read(def);
    	for(int i=2;i<=n;++i)
    	{
    		read(cre[i].lif);
    		read(cre[i].att);
    		read(cre[i].def);
    		read(B[i]);
    		H[i]=(cre[i].lif-1)/(att-cre[i].def);
    		B1[i]=B[i];H1[i]=H[i];
    		q.push(make_pair((double)B[i]/H[i],i));
    	}
    	tag[1]=true;
    	for(int i=1;i<=n;++i)
    		Union_Find::fa[i]=i;
    	while(!q.empty())
    	{
    		int u=q.top().second;q.pop();
    		if(vis[u]) continue;
    		vis[u]=true;
    		if(tag[fa[u]]) {calcu(u);continue;}
    		int x=Union_Find::find(fa[u]);
    		H1[x]+=H1[u],B1[x]+=B1[u];
    		siz[x].push_back(u);
    		Union_Find::fa[u]=x;
    		q.push(make_pair((double)B1[x]/H1[x],x));
    	}
    	printf("%lld
    ",lif);
    	return 0;
    }
    
  • 相关阅读:
    转:js中javascript:void(0) 真正含义
    Chrome Capabilities & ChromeOptions
    scrapy
    远离DoS攻击 Windows Server 2016发布DNS政策
    windows server 2012 AD 活动目录部署系列(五)备份和还原域控制器
    windows server 2012 AD 活动目录部署系列(七)Active Directory 的授权还原
    对AD域进行定期自动备份设置图解
    教程:使用Diskpart创建、扩展或删除磁盘分区
    虚拟化天花板将近,后虚拟化时代如何应对?
    图样图森破 设置虚拟机优先级真的很容易?
  • 原文地址:https://www.cnblogs.com/syc233/p/13867741.html
Copyright © 2020-2023  润新知