省选联测 36
瑞平一下。不叠甲了。反正被我瑞平到的那位看到了大概也不会说什么。而且我也不会瑞平别人。
并不是很能理解放到了自己喜欢的歌就高兴得甚至还表现一下的行为。
然而我像神经病一样的行为大概也不能被理解。这也许从另一个方面说明了人类的悲欢并不相通。
说起来我和 joke3579 的音乐品味不能说是基本重合,也只能说是完全不同了。举个例子,《第三心臟》毫无疑问是很不错的,joke3579 也很喜欢。然而我觉得除了一些小地方值得玩味以外就没什么别的了。然而 joke3579 根本不能接受任何核,前些日子给他一些我非常喜欢的非核曲也是对不上他的味。有时候我们两个都很不知道为什么就走了这么长时间。
算了既然人类的悲欢并不相通那似乎没什么可以评价的了。大概生活方式的不同引起的诸多差异是难以避免的。
太空漫步
大水题。有个 corner cases 是开头是 * 或 [ 。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <bitset>
#include <cstring>
using namespace std;
int n,m,pos[110];
char s[110],t[1000010];
int top,stk[110];
bitset<1000010>dp[110];
int main(){
int tim;scanf("%s%d",s+1,&tim);n=strlen(s+1);
for(int i=1;i<=n;i++){
if(s[i]=='[')stk[++top]=i;
else if(s[i]==']')pos[i]=stk[top],top--;
}
while(tim--){
scanf("%s",t+1);m=strlen(t+1);
dp[0][0]=1;
for(int i=1;i<=n;i++){
dp[i].reset();
bool tmp=false;
for(int j=0;j<=m;j++){
tmp|=dp[i-1][j];
if(j){
if(s[i]=='N'||s[i]=='S'||s[i]=='E'||s[i]=='W')dp[i][j]=dp[i-1][j-1]&(s[i]==t[j]);
if(s[i]=='?')dp[i][j]=dp[i-1][j-1];
}
if(s[i]=='*')dp[i][j]=tmp;
if(s[i]=='[')dp[i][j]=dp[i-1][j];
if(s[i]==']')dp[i][j]=dp[i-1][j]|dp[pos[i]][j];
}
}
for(int i=1;i<=m;i++)putchar(dp[n][i]+'0');puts("");
}
return 0;
}
树的解构
小水题。
期望线性性每个节点可以拆开算。观察发现每个节点的贡献只和深度有关。每次往最上边加一条边的贡献是
卡常,别写 vector。
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int mod=998244353;
int n,ans,inv[2000010];
int read(){
int x=0;char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x;
}
struct node{
int v,next;
}edge[2000010];
int t,head[2000010];
void add(int u,int v){
edge[++t].v=v;edge[t].next=head[u];head[u]=t;
}
void dfs(int x,int d){
ans=(ans+inv[d])%mod;
for(int i=head[x];i;i=edge[i].next)dfs(edge[i].v,d+1);
}
int main(){
n=read();inv[1]=1;
for(int i=2;i<=n;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=n;i++)inv[i]=(inv[i-1]+inv[i])%mod;
for(int i=2;i<=n;i++){
int f;scanf("%d",&f);add(f,i);
}
dfs(1,1);
printf("%d\n",ans);
return 0;
}
小 T 与灵石
根据链的情况,推断每次操作只有距离最远的两个点有贡献。那么找到中点打标记,变成每个点到标记点的最小距离。这个可以处理一个向上的标记一个向下的标记来搞。向上的标记代表下面的标记点的深度最小值,向下的标记同理。最后两次 dfs,第一次下推向上的标记,第二次用向上的标记下推向下的标记,差不多就是个换根。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int n,q;
struct node{
int v,next;
}edge[300010];
int t,head[300010],ans[300010],a[1000010],up[300010],down[300010];
void add(int u,int v){
edge[++t].v=v;edge[t].next=head[u];head[u]=t;
}
int num,dfn[300010],rk[300010],fa[300010],top[300010],son[300010],size[300010],dep[300010];
void dfs1(int x,int f){
dep[x]=dep[f]+1;fa[x]=f;size[x]=1;
for(int i=head[x];i;i=edge[i].next){
dfs1(edge[i].v,x);
size[x]+=size[edge[i].v];
if(size[son[x]]<size[edge[i].v])son[x]=edge[i].v;
}
}
void dfs2(int x,int tp){
dfn[x]=++num;rk[num]=x;top[x]=tp;
if(son[x])dfs2(son[x],tp);
for(int i=head[x];i;i=edge[i].next){
if(edge[i].v!=son[x])dfs2(edge[i].v,edge[i].v);
}
}
int lca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
return x;
}
int dis(int x,int y){
return dep[x]+dep[y]-2*dep[lca(x,y)];
}
int getk(int x,int k){
if(x==1)return x;
while(k){
int ret=min(k,dfn[x]-dfn[top[x]]);
x=rk[dfn[x]-ret];k-=ret;
if(x==1)return x;
if(!k)break;
x=fa[x];k--;
}
return x;
}
void dfs3(int x){
for(int i=head[x];i;i=edge[i].next){
dfs3(edge[i].v);
up[x]=min(up[x],up[edge[i].v]);
}
}
void dfs4(int x){
down[x]=min(down[x],up[x]-2*dep[x]);
for(int i=head[x];i;i=edge[i].next){
down[edge[i].v]=min(down[edge[i].v],down[x]);
dfs4(edge[i].v);
}
}
int main(){
scanf("%d",&n);
for(int i=2;i<=n;i++){
int f;scanf("%d",&f);add(f,i);
}
dfs1(1,0);dfs2(1,1);
for(int i=1;i<=n;i++)up[i]=down[i]=2*n;
scanf("%d",&q);
while(q--){
int k;scanf("%d",&k);
for(int i=1;i<=k;i++)scanf("%d",&a[i]);
int mx=0,x=a[1],y=a[1];
for(int i=2;i<=k;i++){
int d=dis(a[1],a[i]);
if(mx<d)mx=d,x=a[i];
}
mx=0;
for(int i=1;i<=k;i++){
int d=dis(x,a[i]);
if(mx<d)mx=d,y=a[i];
}
if(dep[x]<dep[y])swap(x,y);
int d=dis(x,y);
int mid=getk(x,d>>1);
down[mid]=min(down[mid],d-dep[x]);
if(d&1)up[fa[mid]]=min(up[fa[mid]],dep[x]);
else up[mid]=min(up[mid],dep[x]);
}
dfs3(1);dfs4(1);
for(int i=1;i<=n;i++)printf("%d\n",down[i]+dep[i]);
return 0;
}
小 S 埋地雷
loj6611。很神秘的区间 dp。
设
转移枚举最晚删除
然而转移有坑。具体的,这个
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
int n,dp[80][80][80][80],p[80],q[80],r[80],s[80];
int w(int a,int b,int c,int d){
return (p[a]-q[b])*(p[a]-q[b])+(p[b]-r[c])*(p[b]-r[c])+(p[c]-s[d])*(p[c]-s[d]);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&p[i]);
for(int i=1;i<=n;i++)scanf("%d",&q[i]);
for(int i=1;i<=n;i++)scanf("%d",&r[i]);
for(int i=1;i<=n;i++)scanf("%d",&s[i]);
for(int len=1;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
for(int t=j+1;t<=n+1;t++){
for(int u=i;u<=j;u++){
for(int k=u;k<=j;k++){
for(int v=k+1;v<=j+1;v++){
dp[i][j][t][u]=max(dp[i][j][t][u],dp[i][k-1][v][(u==k)?i:u]+dp[k+1][j][t][(v==j+1)?k+1:v]+w(i-1,k,j+1,t));
}
}
}
}
}
}
printf("%d\n",dp[1][n][n+1][1]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现