• Comet OJ


    比赛链接:https://www.cometoj.com/contest/74

    T1

    首先无论如何操作都不会改变整个序列的和,故直接判掉两个序列和不相同的情况

    接下来根据操作定义不难知道:({b_i})中的每个非零项都对应着({a_i})中的一段数的和,每一段不会相交,所有的这些段拼起来正好就是原序列。那么我们维护当前已经被覆盖的序列({a_i})的右端点,每次扫到非零({b_i})时再暴力向右拓展即可

    统计答案:每将一段({a_i})变成一个(b_i)需要恰好一次操作,但是如果恰好有(a_i=b_i)则不需要操作。注意此时(a_i=0)对判断的影响,可以把(0)也算进来,判断(i)是否在这一段区间里即可

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<vector>
    #include<math.h>
    #include<queue>
    #include<set>
    #include<map>
    using namespace std;
    typedef long long ll;
    typedef long double db;
    typedef pair<int,int> pii;
    const int N=10000;
    const db pi=acos(-1.0);
    #define lowbit(x) (x)&(-x)
    #define sqr(x) (x)*(x)
    #define rep(i,a,b) for (register int i=a;i<=b;i++)
    #define per(i,a,b) for (register int i=a;i>=b;i--)
    #define fir first
    #define sec second
    #define mp(a,b) make_pair(a,b)
    #define pb(a) push_back(a)
    #define maxd 998244353
    #define eps 1e-8
    int n,a[100100],b[100100];
    
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
        while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
        return x*f;
    }
    
    int main()
    {
    	//freopen("begin2.in","r",stdin);
    	int T=read();
    	while (T--)
    	{
    		n=read();
    		ll sum1=0,sum2=0;
    		rep(i,1,n) {a[i]=read();sum1+=a[i];}
    		rep(i,1,n) {b[i]=read();sum2+=b[i];}
    		if (sum1!=sum2) {puts("-1");continue;}
    		//cout << sum1 << endl;
    		int r=1,ok=1,ans=0;
    		rep(i,1,n)
    		{
    			if (!b[i]) continue;
    			ll sum=0;ans++;
    			int l=r;
    			while ((sum<b[i]) && (r<=n)) {sum+=a[r];r++;}
    			if (sum!=b[i]) {ok=0;break;}
    			if ((i>=l) && (i<=r-1) && (a[i]==b[i])) ans--;
    			//cout << i << " "<< l << " " << r-1 << endl;
    		}
    		if (ok) printf("%d
    ",ans);
    		else puts("-1");
    	}
    	return 0;
    }
    

    T2

    注意到这里“最短的路径”一定满足该路径的上的边权最大值最小

    对于((s,t))路径上的边权最大值最小的边,我们可以通过mst求出来,之后递归下去

    发现每一次递归都是干同样的事情,也就是说((s,t))的最短路就是其在(mst)上的路径

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<vector>
    #include<math.h>
    #include<queue>
    #include<set>
    #include<map>
    using namespace std;
    typedef long long ll;
    typedef long double db;
    typedef pair<int,int> pii;
    const int N=10000;
    const db pi=acos(-1.0);
    #define lowbit(x) (x)&(-x)
    #define sqr(x) (x)*(x)
    #define rep(i,a,b) for (register int i=a;i<=b;i++)
    #define per(i,a,b) for (register int i=a;i>=b;i--)
    #define fir first
    #define sec second
    #define mp(a,b) make_pair(a,b)
    #define pb(a) push_back(a)
    #define maxd 998244353
    #define eps 1e-8
    struct node{int to,nxt,cost;}sq[600600];
    int all=0,head[300300];
    int n,m,q,fa[300300][20],f[300300],dep[300300];
    ll dis[300300],bin[300300];
    
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
        while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
        return x*f;
    }
    
    int find(int x)
    {
    	if (f[x]==x) return x;
    	f[x]=find(f[x]);
    	return f[x];
    }
    
    void add(int u,int v,int w)
    {
    	all++;sq[all].to=v;sq[all].nxt=head[u];sq[all].cost=bin[w];head[u]=all;
    }
    
    void dfs(int u,int fu)
    {
    	dep[u]=dep[fu]+1;fa[u][0]=fu;
    	rep(i,1,19) fa[u][i]=fa[fa[u][i-1]][i-1];
    	for (int i=head[u];i;i=sq[i].nxt)
    	{
    		int v=sq[i].to;
    		if (v==fu) continue;
    		dis[v]=(dis[u]+sq[i].cost)%maxd;
    		dfs(v,u);
    	}
    }
    
    int LCA(int u,int v)
    {
    	if (dep[u]<dep[v]) swap(u,v);
    	int tmp=dep[u]-dep[v];
    	per(i,19,0)
    		if ((tmp>>i)&1) u=fa[u][i];
    	if (u==v) return u;
    	per(i,19,0)
    		if (fa[u][i]!=fa[v][i]) 
    		{
    			u=fa[u][i];v=fa[v][i];
    		}
    	return fa[u][0];
    }
    
    int main()
    {
    	n=read();m=read();
    	rep(i,1,n) f[i]=i;
    	bin[0]=1;
    	rep(i,1,m) bin[i]=bin[i-1]*2%maxd;
    	rep(i,1,m)
    	{
    		int x=read(),y=read();
    		int fx=find(x),fy=find(y);
    		if (fx!=fy)
    		{
    			add(x,y,i);add(y,x,i);
    			f[fx]=fy;
    		}
    	}
    	dfs(1,0);
    	//rep(i,1,n) cout << dep[i] << " ";cout << endl;
    	int q=read();
    	while (q--)
    	{
    		int u=read(),v=read(),w=LCA(u,v);
    		ll ans=dis[u]+dis[v]-dis[w]*2;
    		ans=(ans%maxd+maxd)%maxd;
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    

    T3

    首先决定({a_i})的顺序,假设所有人均发动攻击,那么每个人对答案的贡献分别是乘上系数(frac{1}{2^n},frac{1}{2^{n-1}},cdots,frac{1}{2}),故将原序列从小到大排序是最优的

    接下来不难列出期望dp的式子:(f_i=frac{1}{2}f_{i-1}+frac{f_{i-1}+a_i}{2}),整理得(f_i=frac{3}{4}f_{i-1}+frac{1}{4}a_i),直接做显然会超时。

    考虑每个(a_i)(f_n)的贡献,可以写成(f_n=sum_{i=1}^nfrac{1}{4}·(frac{3}{4})^{n-i}a_i),这样(a_i)对答案的影响只会和它的排名有关,用权值线段树维护,维护(f)和排名。由于(a_i)很大于是写了个动态开点(但是常数很大)

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<vector>
    #include<math.h>
    #include<queue>
    #include<set>
    #include<map>
    using namespace std;
    typedef long long ll;
    typedef long double db;
    typedef pair<int,int> pii;
    const int N=1e9;
    const db pi=acos(-1.0);
    #define lowbit(x) (x)&(-x)
    #define sqr(x) (x)*(x)
    #define rep(i,a,b) for (register int i=a;i<=b;i++)
    #define per(i,a,b) for (register int i=a;i>=b;i--)
    #define fir first
    #define sec second
    #define mp(a,b) make_pair(a,b)
    #define pb(a) push_back(a)
    #define maxd 998244353
    #define eps 1e-8
    int rt=0,n,m,q,tot=0,a[100100],siz[3903000],lson[3903000],rson[3903000];
    ll seg[3900300],tag[3903000],inv34,inv43,f[100100];
    
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
        while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
        return x*f;
    }
    
    int add(int x,int y)
    {
    	int ans=x+y;
    	if (ans>=maxd) ans-=maxd;
    	return ans;
    }
    
    ll qpow(ll x,int y)
    {
    	ll ans=1;
    	while (y)
    	{
    		if (y&1) ans=ans*x%maxd;
    		x=x*x%maxd;y>>=1;
    	}
    	return ans;
    }
    
    void pushdown(int id)
    {
    	if (tag[id]!=1)
    	{
    		if (lson[id]) 
    		{
    			seg[lson[id]]=seg[lson[id]]*tag[id]%maxd;
    			tag[lson[id]]=tag[lson[id]]*tag[id]%maxd;
    		}
    		if (rson[id])
    		{
    			seg[rson[id]]=seg[rson[id]]*tag[id]%maxd;
    			tag[rson[id]]=tag[rson[id]]*tag[id]%maxd;
    		}
    		tag[id]=1;
    	}
    }
    
    void modify(int &id,int l,int r,int pos,ll val,int v)
    {
    	if (!id) {id=(++tot);tag[id]=1;}
    	pushdown(id);
    	seg[id]=(seg[id]+val+maxd)%maxd;siz[id]+=v;
    	if (l==r) return;
    	int mid=(l+r)>>1;
    	if (pos<=mid) modify(lson[id],l,mid,pos,val,v);
    	else modify(rson[id],mid+1,r,pos,val,v);
    }
    
    void modifyr(int &id,int l,int r,int ql,int qr,ll val)
    {
    	if (!id) {id=(++tot);tag[id]=1;}
    	if ((l>qr) || (r<ql)) return;
    	pushdown(id);
    	if ((l>=ql) && (r<=qr))
    	{
    		seg[id]=seg[id]*val%maxd;
    		tag[id]=tag[id]*val%maxd;
    		return;
    	}
    	int mid=(l+r)>>1;
    	if (ql<=mid) modifyr(lson[id],l,mid,ql,qr,val);
    	if (qr>mid) modifyr(rson[id],mid+1,r,ql,qr,val);
    	seg[id]=(seg[lson[id]]+seg[rson[id]])%maxd;
    }
    
    int query(int id,int l,int r,int ql,int qr)
    {
    	if (!id) return 0;
    	if ((l>qr) || (r<ql)) return 0;
    	if ((l>=ql) && (r<=qr)) return siz[id];
    	int mid=(l+r)>>1;int ans=0;
    	if (ql<=mid) ans+=query(lson[id],l,mid,ql,qr);
    	if (qr>mid) ans+=query(rson[id],mid+1,r,ql,qr);
    	return ans;
    }
    
    void add(int x)
    {
    	int k=query(rt,0,N,x,N)+1;
    	modify(rt,0,N,x,f[k]*x%maxd,1);
    	if (x) modifyr(rt,0,N,0,x-1,inv34);
    }
    
    void del(int x)
    {
    	int k=query(rt,0,N,x,N);
    	modify(rt,0,N,x,-f[k]*x%maxd,-1);
    	if (x) modifyr(rt,0,N,0,x-1,inv43);
    }
    
    void init()
    {
    	inv34=qpow(4,maxd-2)*3%maxd;
    	inv43=qpow(3,maxd-2)*4%maxd;
    	f[1]=qpow(4,maxd-2);
    	rep(i,2,n) f[i]=f[i-1]*inv34%maxd;
    }
    
    int main()
    {
    	//freopen("relation3.in","r",stdin);
    	//freopen("a.out","w",stdout);
    	n=read();init();
    	rep(i,1,n) {a[i]=read();add(a[i]);}
    	printf("%lld
    ",seg[rt]);
    	q=read();
    	while (q--)
    	{
    		int pos=read(),val=read();
    		del(a[pos]);a[pos]=val;add(a[pos]);
    		printf("%lld
    ",seg[rt]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    在仅有的一次生命里活出自己最大的可能
    每个人都渴望赞美
    历练领导力的八字要诀
    爱情语录
    Ps
    别跟我要钱,我是教授
    改变人生的五个问题
    纪晓岚妙用口才
    智慧和智商
    经典
  • 原文地址:https://www.cnblogs.com/encodetalker/p/11831115.html
Copyright © 2020-2023  润新知