这场打的很烂,说明我对组合数学的掌握(二项式定理,以及递推式的思考方向)都不太好。而且,我做题的思路也很有问题。就是完全凭借灵感,自己没有脑子一样思路就被题目带跑了,根本跳不出来,看到题目也不会分析,直接找到一个缝隙就开始钻牛角尖。以后看到题目除了分析性质外,再把思路打开一些多考虑几种可能了再往下想(像我这种记性不好的最好在草稿纸上记一下)
当然比赛或者补题的时候,也暴露了平时学知识的一些问题,不会深入探究(就比如矩阵没有交换律为什么树上ddp线段树P_up()通常交换顺序乘起来是对的?)

[SNOI2017 DAY1]礼物

  • 题意:略
  • 思路:
    \(S_i=\sum_{i=1}^n A_i\)
    \(A_i=S_{i-1}+i^k\)
    \(S_i=2*S_{i-1}+i^k\)
    因为这个我也不会化成\(O(1)\)可以直接求的函数,所以看到\(m=10\)考虑最近学的矩阵快速幂(怎么搞出跟\(m\)有关的矩阵呢?)
    发现\(n^k=((n-1)+1)^k=\sum_{i=0}^k C_k^i*(n-1)^i\)
    然后发现其中的\((n-1)^i\)可以记录并用上面同样的公式递推的,因此按照\([f_i,i^k,i^{k-1}...i^1,i^0]\)这么构建矩阵,然后由倒着的杨辉三角构成系数矩阵。求矩阵快速幂即可。
  • code:
#include<bits/stdc++.h>
using namespace std;
const int N=105;
const int mod=1e9+7;
typedef long long ll;
ll C[N][N],inf=1e18;
int K;
struct matr {
	ll z[13][13];
	matr friend operator*(matr u,matr v) {
		matr w;
		for(int i=0;i<=K+1;i++) for(int j=0;j<=K+1;j++) {
			ll tmp=0;
			for(int k=0;k<=K+1;k++)tmp=(tmp+u.z[i][k]*v.z[k][j])%mod;
			w.z[i][j]=tmp;
		}
		return w;
	}
}a;
void init_C() {
	C[0][0]=1;
	for(int i=1;i<=K;i++) {
		C[i][0]=1;
		for(int j=1;j<=i;j++) {
			C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
		}
	}
}
void Build() {
	for(int i=0;i<=K+1;i++)for(int j=0;j<=K+1;j++)a.z[i][j]=0;
	a.z[0][0]=2;for(int j=K;j>=0;j--)a.z[0][K-j+1]=C[K][j];
	for(int i=1;i<=K+1;i++) {
		int k=K-i+1;
		for(int j=0;j<=k;j++) a.z[i][K+1-j]=C[k][j];
	}

}
ll Ksm(ll b) {
	matr mul=a;b--;
	for(;b;b>>=1,a=a*a) {
		if(b&1)mul=mul*a;
	}
	return mul.z[0][K+1];
}
ll ksm(ll w,ll b) {ll mul=1;w%=mod;for(;b;b>>=1,w=w*w%mod)if(b&1)mul=mul*w%mod;return mul;}
int main() {
	ll n;scanf("%lld%d",&n,&K);
	if(n==1) {printf("1");return 0;}
	init_C();
	Build();
	ll res=Ksm(n-1);
//	printf("%lld\n",res);
	printf("%lld",(res+ksm(n,K))%mod);
	return 0;
}

可变地图

  • 思路:
    为了不重不漏而且保证不会左右横跳。
    状态\(dp[i][j]\)由上层\(dp[i-1][k]\)转移时,保证按照\((i-1,k)->(i,k)-..->(i,j)\)方式走。
    然后递推系数矩阵很好造。
    ps.注意那个P_up是右边*左边
  • code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
const int M=13;
const int mod=1e9+7;
int mp[N][M],n,m,K,ls[N],rs[N],Tcnt;
char ch[N][M];
struct matr {
	ll z[10][10];
	matr friend operator*(matr u,matr v) {
		matr w;
		for(int i=0;i<m;i++) for(int j=0;j<m;j++) {
			ll tmp=0;for(int k=0;k<m;k++)tmp=(tmp+u.z[i][k]*v.z[k][j])%mod;
			w.z[i][j]=tmp;
		}
		return w;
	}
};
struct seg {int l,r;matr w;}T[N];
void Give(matr &tmp,int h) {
	for(int i=0;i<m;i++)for(int j=0;j<m;j++)tmp.z[i][j]=0;
	int pre=-1;
	for(int j=0;j<m;j++) {
		if(mp[h][j]==1) {
			for(int x=pre+1;x<j;x++)for(int y=pre+1;y<j;y++) tmp.z[x][y]=1;
			pre=j;
		}
	}
	if(pre<m-1) {
		for(int x=pre+1;x<m;x++)for(int y=pre+1;y<m;y++)tmp.z[x][y]=1;
	}
}
void P_up(int x) {T[x].w=T[rs[x]].w*T[ls[x]].w;}
void Build(int &x,int l,int r) {
	x=++Tcnt;T[x].l=l,T[x].r=r;
	if(l==r) {Give(T[x].w,l);return;}
	int mid=(l+r)>>1;
	Build(ls[x],l,mid),Build(rs[x],mid+1,r);
	P_up(x);
}
void Update(int x,int h) {
	if(T[x].l==T[x].r) {Give(T[x].w,h);return;}
	int mid=(T[x].l+T[x].r)>>1;
	if(h<=mid)Update(ls[x],h);
	else Update(rs[x],h);
	P_up(x);
}
int main() {
	scanf("%d%d%d",&n,&m,&K);
	for(int i=1;i<=n;i++) {
		scanf("%s",ch[i]);
		for(int j=0;j<m;j++)mp[i][j]=ch[i][j]-'0';
	}
	int rt;if(n>=2)Build(rt,2,n);
	for(int i=1;i<=K;i++) {
		int p,x,y;scanf("%d%d%d",&p,&x,&y);y--;
		if(p==1) {
			mp[x][y]^=1;
			if(x>1)Update(rt,x);
		}
		else {
			x--;
			if(mp[1][x]) {printf("0\n");}
			else {
				int l,r;l=r=x;
				while(l>0&&!mp[1][l-1]) l--;
				while(r<m-1&&!mp[1][r+1])r++;
				if(n==1) {printf("%d\n",(y>=l&&y<=r));}
				else {
					matr res=T[rt].w;
//					printf("![%d,%d](%d)\n",l,r,mp[1][r]);
					ll ans=0;for(int j=l;j<=r;j++) ans=(ans+res.z[y][j])%mod;
					printf("%lld\n",ans);
				}
			}
		}
	}
	return 0;
}

最大连通子块和

  • 思路:不想写柿子了,很好推啦。就是更新g[]时删除并取max,这个可以用垃圾堆或者muitiset来维护。
  • code
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
const int M=2e5+5;
typedef long long ll;
int Tcnt,ls[N],rs[N],nxt[M<<1],to[M<<1],head[M],ecnt,top[M],sz[M],ed[M],son[M],fa[M],dfn[M],b[M],Time,rt[N];
priority_queue<ll> Q[M],_Q[M];
ll a[M],inf=1e17,f[M][2],g[M][2];
void add_edge(int u,int v) {nxt[++ecnt]=head[u];to[ecnt]=v;head[u]=ecnt;}
void gt_son(int u) {
	sz[u]=1;
	for(int i=head[u];i;i=nxt[i]) {
		int v=to[i];if(v==fa[u])continue;
		fa[v]=u;gt_son(v);sz[u]+=sz[v];
		if(sz[son[u]]<sz[v]) son[u]=v;
	}
}
void gt_top(int u,int Tp) {
	top[u]=Tp;ed[Tp]=u;dfn[u]=++Time;b[Time]=u;
	if(son[u])gt_top(son[u],Tp);
	for(int i=head[u];i;i=nxt[i]) {
		int v=to[i];if(v==fa[u]||v==son[u])continue;
		gt_top(v,v);
	}
}
void Dp(int u) {
	g[u][1]=a[u];
	for(int i=head[u];i;i=nxt[i]) {
		int v=to[i];if(v==fa[u])continue;
		Dp(v);
		if(v==son[u])f[u][1]=max(f[v][1],0ll),f[u][0]=max(f[v][0],f[v][1]);
		else g[u][1]+=max(f[v][1],0ll),g[u][0]=max(g[u][0],max(f[v][0],f[v][1])),Q[u].push(f[v][0]),Q[u].push(f[v][1]);
	}
	f[u][0]=max(f[u][0],g[u][0]),f[u][1]+=g[u][1];
//	printf("%d: %lld %lld\n",u,f[u][0],f[u][1]);
}
struct matr {
	ll z[3][3];
//	matr() {for(int i=0;i<3;i++)for(int j=0;j<3;j++)z[i][j]=0;}
	matr friend operator*(matr u,matr v) {
		matr w;
		for(int i=0;i<3;i++)for(int j=0;j<3;j++) {
			ll mx=-inf;
			for(int k=0;k<3;k++) mx=max(mx,u.z[i][k]+v.z[k][j]);
			w.z[i][j]=mx;
		}
		return w;
	}
};
void Print(matr x) {
	puts("");
	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++)printf("%lld ",x.z[i][j]);
		puts("");
	}
	puts("");
}
struct seg {int l,r;matr w;}T[N];
void Give(matr &tmp,int x) {tmp.z[0][2]=g[x][0];tmp.z[1][1]=tmp.z[1][2]=g[x][1];}
void Nw(matr &tmp) {tmp.z[0][0]=tmp.z[0][1]=tmp.z[2][2]=0;tmp.z[1][0]=tmp.z[2][0]=tmp.z[2][1]=-inf;}
void P_up(int x) {T[x].w=T[ls[x]].w*T[rs[x]].w;}
void Build(int &x,int l,int r) {
	x=++Tcnt;T[x].l=l,T[x].r=r;
	if(l==r) {Nw(T[x].w);Give(T[x].w,b[l]);return;}
	int mid=(l+r)>>1;
	Build(ls[x],l,mid);Build(rs[x],mid+1,r);
	P_up(x);
}
void Update(int x,int p,int y) {
	if(T[x].l==T[x].r) {Give(T[x].w,y);return;}
	int mid=(T[x].l+T[x].r)>>1;
	if(p<=mid)Update(ls[x],p,y);
	else Update(rs[x],p,y);
	P_up(x);
}
matr Query(int x,int l,int r) {
	if(l<=T[x].l&&T[x].r<=r) {return T[x].w;}
	int mid=(T[x].l+T[x].r)>>1;bool f1=0;matr res;
	if(l<=mid) {f1=1;res=Query(ls[x],l,r);}
	if(r>mid) {
		if(!f1)res=Query(rs[x],l,r);
		else res=res*Query(rs[x],l,r);
	}
	return res;
}
struct node {ll _0,_1;};
node Ask(int u,int tp) {
	matr res=Query(rt[tp],dfn[u],dfn[ed[tp]]);
//	Print(res);
//	printf("!%d [%d,%d]\n",rt[tp],dfn[u],dfn[ed[tp]]);
	return (node){max(res.z[0][0],max(res.z[0][1],res.z[0][2])),max(res.z[1][0],max(res.z[1][1],res.z[1][2]))};
}
void change(int x,ll y) {
	g[x][1]+=y-a[x];a[x]=y;
	int v=x;
	while(v) {
		int u=top[v];
		Update(rt[u],dfn[v],v);
		node nw=Ask(u,u);
		v=fa[u];
//		printf("%d: %lld %lld\n",v,g[v][0],g[v][1]);
		g[v][1]+=max(0ll,nw._1)-max(0ll,f[u][1]);
		_Q[v].push(f[u][0]);_Q[v].push(f[u][1]);Q[v].push(nw._0);Q[v].push(nw._1);
		while(!_Q[v].empty()&&_Q[v].top()==Q[v].top()) {_Q[v].pop();Q[v].pop();}
		g[v][0]=Q[v].top();
		f[u][0]=nw._0,f[u][1]=nw._1;
//		printf("%d: %lld %lld\n",v,g[v][0],g[v][1]);
	}
}
int main() {
//	freopen("data.in","r",stdin);
//	freopen("sb.out","w",stdout);
	int n,m;scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	for(int i=1;i<n;i++) {int u,v;scanf("%d%d",&u,&v);add_edge(u,v),add_edge(v,u);}
	gt_son(1);gt_top(1,1);Dp(1);
	for(int i=1;i<=n;i++) {
		int j=dfn[ed[b[i]]];
		Build(rt[b[i]],i,j);i=j;
	}
	for(int i=1;i<=m;i++) {
		char ch[3];int x;ll y;scanf("%s",ch);
		if(ch[0]=='Q') {
			scanf("%d",&x);
			if(top[x]==x)printf("%lld\n",max(f[x][0],f[x][1]));
			else {
				node ans=Ask(x,top[x]);
				printf("%lld\n",max(ans._0,ans._1));
			}
		}
		else {
			scanf("%d%lld",&x,&y);
			change(x,y);
		}
	}
	return 0;
}