这场打的很烂,说明我对组合数学的掌握(二项式定理,以及递推式的思考方向)都不太好。而且,我做题的思路也很有问题。就是完全凭借灵感,自己没有脑子一样思路就被题目带跑了,根本跳不出来,看到题目也不会分析,直接找到一个缝隙就开始钻牛角尖。以后看到题目除了分析性质外,再把思路打开一些多考虑几种可能了再往下想(像我这种记性不好的最好在草稿纸上记一下)
当然比赛或者补题的时候,也暴露了平时学知识的一些问题,不会深入探究(就比如矩阵没有交换律为什么树上ddp线段树P_up()通常交换顺序乘起来是对的?)
[SNOI2017 DAY1]礼物
- 题意:略
- 思路:
因为这个我也不会化成可以直接求的函数,所以看到考虑最近学的矩阵快速幂(怎么搞出跟有关的矩阵呢?)
发现
然后发现其中的可以记录并用上面同样的公式递推的,因此按照这么构建矩阵,然后由倒着的杨辉三角构成系数矩阵。求矩阵快速幂即可。 - 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;
}
可变地图
- 思路:
为了不重不漏而且保证不会左右横跳。
状态由上层转移时,保证按照方式走。
然后递推系数矩阵很好造。
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("\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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人