2018.9.20 离线赛 by KanaD

T1——diamond(3923)

Description:

有一个 n ∗ n n*n nn的矩形,每个格 ( i , j ) (i,j) (i,j)上的权值是数 i + j i+j i+j的奇数码之和与偶数码之和之差的绝对值. e g : 3241 = ∣ ( 2 + 4 ) − ( 1 + 3 ) ∣ eg: 3241=|(2+4)-(1+3)| eg:3241=(2+4)(1+3).这样有 q q q组询问.
n , q ≤ 1 0 6 n , q \le 10^6 n,q106

Solution:

  • 首先观察一下这个矩形的数 i + j i+j i+j的分布,不难发现数 2 2 2$n+1$出现了$i-1$次,而$n+2$ n + n n+n n+n的出现次数也是与之对称的.
  • 这样的话,就可以先预处理出每个数的权值以及权值前缀和和后缀和.
  • 那么对于询问就是前缀和、后缀和做一下差即可.

Code:

#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long 
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;
template<class T>inline void Rd(T &x){
	x=0;char c;int f=1;
	while((c=getchar())<48)if(c=='-')f=-1;
	do x=(x<<1)+(x<<3)+(c^48);
	while((c=getchar())>47);
	x*=f;
}

#define N 1000005

int Abs(int x){return x>0?x:-x;}
ll num[N<<1],sum[N<<1],f1[N<<1],f2[N<<1];

int calc(int x){
	int sum1=0,sum2=0,y;
	for(int i=1;x;x/=10,++i){
		y=x%10;
		if(y&1)sum1+=y;
		else sum2+=y;
	}
	return Abs(sum1-sum2);
}

void Init(){
	SREP(i,2,N<<1)num[i]=calc(i);
	SREP(i,2,N<<1)sum[i]=sum[i-1]+num[i];
	SREP(i,2,N<<1)f1[i]=f1[i-1]+num[i]*(i-1);
	DREP(i,(N<<1)-1,1)f2[i]=f2[i+1]+num[i]*((N<<1)-i+1);
}

int main(){
//	freopen("diamond.in","r",stdin);
//	freopen("diamond.out","w",stdout);
	
	Init();
	
	int cas,n;Rd(cas);
	while(cas--) Rd(n),printf("%lld\n",f1[n]+f2[n+1]-f2[2*n+1]-(sum[2*n]-sum[n])*((N<<1)-(2*n)));
	
	return 0;
}

T1——biscuit(3924)

Description:

有一个长度为 n n n的序列 A A A,对于 A i ≤ x A_i \le x Aix,有 q q q个区间 [ l i , r i ] [l_i,r_i] [li,ri],求这个 q q q个区间的最小值的最大值得期望.
n , x , q ≤ 2000 n , x , q \le 2000 n,x,q2000

Solution:

Code:

#include<bits/stdc++.h>
using namespace std;
#define REP(i,dp,t)for(int i=(dp),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,dp,t)for(int i=(dp),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,dp,t)for(int i=(dp),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long 
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;
template<class T>inline void Rd(T &x){
	x=0;char c;int dp=1;
	while((c=getchar())<48)if(c=='-')dp=-1;
	do x=(x<<1)+(x<<3)+(c^48);
	while((c=getchar())>47);
	x*=dp;
}

#define N 2002
#define mod 1000000007

int n,x,q;

struct node{
	int l,r;
	bool operator<(const node &_)const{
		return l==_.l?r>_.r:l<_.l;
	}
}Q[N];

void Add(ll &x,ll y){
	x+=y;
	if(x>=mod)x-=mod;
	else if(x<0)x+=mod;
}

ll Pow(ll a,ll b){
	ll x=1;
	while(b){
		if(b&1)x=x*a%mod;
		a=a*a%mod,b>>=1;
	}
	return x;
}

struct p20{
	
	int A[20];
	ll sum,ans;
	
	void solve(){
		REP(i,1,n) A[i]=1;
		
		while(1){
			int Mx=0;
			REP(i,1,q){
				int Mn=A[Q[i].r];
				SREP(j,Q[i].l,Q[i].r) chkmin(Mn,A[j]);
				chkmax(Mx,Mn);
			}
			Add(ans,Mx); 
			Add(sum,1);
			int p=1;
			while(p<=n && A[p]==x){
				A[p]=1;
				++p;
			}
			if(p>n)break;
			++A[p];
		}
		printf("%lld\n",ans*Pow(sum,mod-2)%mod);
	}
}p1;

struct p40{
	
	ll ans;
	
	void solve(){
		int m=Q[1].r-Q[1].l+1;
		REP(i,1,x) Add(ans,(Pow(x-i+1,m)-Pow(x-i,m))*i%mod);
		printf("%lld\n",(ans*Pow(Pow(x,m),mod-2)%mod+mod)%mod);
	}
}p2;

struct p80{
	
	ll ans;
	ll inv[N],dp[N];
	
	int stk[N],top;
	int nxt[N],pre[N];
	int L,R;
	
	void Init(){
		sort(Q+1,Q+1+q);
		REP(i,1,q){
			while(Q[i].r<=Q[stk[top]].r)--top;
			stk[++top]=i;
		}
		q=top;
		REP(i,1,q)Q[i]=Q[stk[i]];
		
		L=1,R=0;
		REP(i,1,n){
			while(R<q && Q[R+1].l<=i)++R;
			while(L<=q && Q[L].r<i)++L;
			pre[i]=L,nxt[i]=R;
		}
		
	}
	
	void solve(){
		
		Init();
		
		REP(i,1,x){
			int j=0;
			ll s=1,t=1;
			inv[0]=1;
			dp[0]=1;
			ll p=((ll)(i-1+mod)%mod*Pow(x,mod-2))%mod;
			ll pc=(1-p+mod)%mod;
			inv[1]=Pow(pc,mod-2);
			REP(k,2,n) inv[k]=inv[k-1]*inv[1]%mod;
			REP(k,1,n){
				while(j<k && nxt[j]<pre[k]-1)Add(s,-dp[j]*inv[j]%mod+mod),j++;
				dp[k]=s*t%mod*p%mod;
				t=t*pc%mod;
				Add(s,dp[k]*inv[k]%mod);
			}
			s=0;
			t=1;
			for(int k=n;k>=1 && nxt[k]==q;k--) Add(s,dp[k]*t%mod),t=t*pc%mod;
			Add(ans,(1-s+mod)%mod);
		}
		
		printf("%lld\n",ans);
	}
}p3;


int main(){
//	freopen("biscuit.in","r",stdin);
//	freopen("biscuit.out","w",stdout);
	Rd(n),Rd(x),Rd(q);
	REP(i,1,q) Rd(Q[i].l),Rd(Q[i].r);
	
	if(q==1)p2.solve();
	else if(n<=6 && x<=6 && q<=6)p1.solve();
	else p3.solve();
	
	return 0;
}

T3——plague(3925)

Description:

有一棵 n n n个节点的树,现在有一种病毒入侵.
e g : eg: eg: x x x被传播病毒,那么该点会被感染,而二次感染点 x x x,会将病毒向下传播.
q q q个操作:

  1. 将点 x x x传播病毒.
  2. 净化以 x x x为根的子树.
  3. 询问点 x x x是否被感染.

n ≤ 1 0 6 , q ≤ 2 ∗ 1 0 6 n \le 10^6 , q \le 2*10^6 n106,q2106

Solution:

  • 次题乍一看这个传播好像有点麻烦,还需要标记一下…
  • 但仔细想想这应该是一道比较正常的传统数据结构题了…(树剖+线段树)
  • 那么我们先分析一下操作的实际意义:
  • 操作 1 1 1 2 2 2:区间修改,操作 3 3 3:单点查询.(而且这里比较特殊,树剖到 1 1 1即可)
  • 那么问题还是对本题感染操作的理解,我们可以将初始值为 − 1 -1 1,那么每次操作 1 1 1为+1,那么询问即为是否 ≥ 0 \ge 0 0.
  • 那么就是实现难度要注意的细节问题了.

Code:

#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long 
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;
template<class T>inline void Rd(T &x){
	x=0;char c;int f=1;
	while((c=getchar())<48)if(c=='-')f=-1;
	do x=(x<<1)+(x<<3)+(c^48);
	while((c=getchar())>47);
	x*=f;
}

#define N 100002

int n,m;

int qwq,head[N];
struct edge{
	int to,nxt;
}E[N<<1];
void addedge(int x,int y){E[qwq]=(edge){y,head[x]};head[x]=qwq++;}
#define EREP(x) for(int i=head[x];~i;i=E[i].nxt)

int fa[N],sz[N],dep[N],son[N],top[N];
int Lt[N],Rt[N],sgID[N],tim;

struct p50{
	
	int mark[N];
	
	void dfs(int x){
		Lt[x]=++tim;
		sgID[tim]=x;
		EREP(x){
			int y=E[i].to;
			if(y==fa[x])continue;
			dfs(y); 
		}
		Rt[x]=tim;
	}
	
	void go(int x){
//		printf("x=%d\n",x);
		EREP(x){
			int y=E[i].to;
			if(y==fa[x])continue;
			++mark[y];
			if(mark[y]>1) go(y);
		}
	}
	
	void solve(){
		
		dfs(1);
		
		int op,x;
		while(m--){
			Rd(op),Rd(x);
			if(op==1) {
				++mark[x];
//				if(mark[x]>1) EREP(x) if(E[i].to!=fa[x]) ++mark[E[i].to],go(E[i].to);
				if(mark[x]>1) go(x);
			}
			if(op==2) REP(i,Lt[x],Rt[x]) mark[sgID[i]]=0;
			if(op==3) /*printf("cnt=%d ",mark[x]),*/puts(mark[x]?"Yes":"No");
		}
	}
}p1;

struct p100{

	void dfs1(int x){
		sz[x]=1;
		son[x]=0;
		dep[x]=dep[fa[x]]+1;
		EREP(x){
			int y=E[i].to;
			if(y==fa[x])continue;
			dfs1(y);
			sz[x]+=sz[y];
			if(sz[son[x]]<sz[y])son[x]=y;
		}
	}
	
	void dfs2(int x,int tp){
		Lt[x]=++tim;
		sgID[tim]=x;
		top[x]=tp;
		if(son[x])dfs2(son[x],tp);
		EREP(x){
			int y=E[i].to;
			if(y==fa[x] || y==son[x])continue;
			dfs2(y,y);
		}
		Rt[x]=tim;
	}
	
	struct Tree{
		#define lson L,mid,p<<1
		#define rson mid+1,R,p<<1|1
		#define family tree[p],tree[p<<1],tree[p<<1|1]
		
		struct node{
			int L,R;
			int sum,mx;
			bool add;
		}tree[N<<2];
		
		void Change(node &A){
			A.add=1;
			A.mx=-1;
			A.sum=-(A.R-A.L+1);
		}
		
		void Down(node &A,node &L,node &R){
			if(!A.add)return;
			Change(L),Change(R);
			A.add=0;
		}
		
		void Up(node &A,node L,node R){
			chkmax(A.mx=R.mx,L.mx+R.sum);
			A.sum=L.sum+R.sum;
		}
		
		void build(int L,int R,int p){
			tree[p].L=L,tree[p].R=R;
			if(L==R){
				tree[p].mx=tree[p].sum=-1;
				return;
			}
			int mid=(L+R)>>1;
			build(lson),build(rson);
			Up(family);
		}
		
		void update1(int L,int R,int p){
			if(tree[p].L==L && tree[p].R==R){
				Change(tree[p]);
				return;
			}
			Down(family);
			int mid=(tree[p].L+tree[p].R)>>1;
			if(R<=mid)update1(L,R,p<<1);
			else if(L>mid)update1(L,R,p<<1|1);
			else update1(lson),update1(rson);
			Up(family); 
		}
		
		void update2(int x,int p,int v){
			if(tree[p].L==tree[p].R){
				tree[p].mx+=v;
				tree[p].sum+=v;
				return;
			}
			Down(family);
			int mid=(tree[p].L+tree[p].R)>>1;
			if(x<=mid)update2(x,p<<1,v);
			else update2(x,p<<1|1,v);
			Up(family);
		}
		
		node query(int L,int R,int p){
			if(tree[p].L==L && tree[p].R==R)return tree[p];
			Down(family);
			int mid=(tree[p].L+tree[p].R)>>1;
			if(R<=mid)return query(L,R,p<<1);
			else if(L>mid)return query(L,R,p<<1|1);
			else {
				node res;
				Up(res,query(lson),query(rson));
				return res;			
			}
		}
		
		node find(int x){
			node ans=query(Lt[top[x]],Lt[x],1);
			x=fa[top[x]];
			while(x){
				node res=query(Lt[top[x]],Lt[x],1);
				x=fa[top[x]];
				Up(ans,res,ans); 
			}
			return ans;
		}
		
	}T;
	
	void solve(){
		dfs1(1);
		dfs2(1,1);
		T.build(1,n,1);
		
		int op,x;
		while(m--){
			Rd(op),Rd(x);
			if(op==1) T.update2(Lt[x],1,1);
			if(op==2) T.update1(Lt[x],Rt[x],1),T.update2(Lt[x],1,-T.find(x).mx-1);
			if(op==3) puts(T.find(x).mx>-1?"Yes":"No");
		}
	}
}p3;

int main(){
//	freopen("plague.in","r",stdin);
//	freopen("plague.out","w",stdout);
	mcl(head,-1); 
	Rd(n),Rd(m);
	REP(i,2,n){
		Rd(fa[i]);
		addedge(i,fa[i]);
		addedge(fa[i],i);
	}
	
	if(n<=3000 && m<=3000)p1.solve();
	else p3.solve();
	
	return 0;
}

总结:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值