T1 树上的数

考场上比较脑瘫没有想到直接dfs就行了这样是O(n+m)的,傻不拉几地多添了个log,

不过因为accoder的评测机太弱了,绝大多数人的正解都是60分,所以没有什么差别;

直接dfs,d到不能d的点就return就好了

#include<bits/stdc++.h>
#define lid id<<1
#define rid id<<1|1
using namespace std;
inline 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<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,m,a,b;
const int mod=19760817, maxn=5e6+5;
int fa[maxn],q[maxn],sum[2];
int head[maxn],num;
struct edge{int to,nxt;}e[maxn<<1];
inline void add(int x,int y)
{e[++num]=(edge){y,head[x]};head[x]=num;}
bool vis[maxn];
inline void dfs(int x)
{
if(vis[x]) return;
vis[x]=1;++sum[1];
for(int i=head[x];i;i=e[i].nxt)
dfs(e[i].to);
}
signed main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
n=read();m=read();a=read();b=read();
q[1]=read(); int x=read(),y=read();
fa[2]=1; add(1,2); for(int i=3;i<=n;i++)
fa[i]=((1ll*fa[i-1]*a+b)^mod)%(i-1)+1,add(fa[i],i);
sum[1]=0;int ans=0; if(!vis[q[1]])dfs(q[1]);ans^=(n-sum[1]);
for(int i=2;i<=m;i++)
{
q[i]=(((1ll*q[i-1]*x+y)^mod)^(i<<1))%(n-1)+2;
dfs(q[i]);ans^=(n-sum[1]);
}
printf("%d\n",ans);
}

T2 时代的眼泪

看到这个题目的时候有点慌,以为是那个dio题,结果后来发现只是题目一样,一个比较显然的换根

将以x为根变为他的儿子y为根,他的变化量是在除了y的子树之外的点比y小的点的个数减去y的子树里比x小的数的个数

可以先dfs出来根为1的最终答案,然后用树状数组处理出对应变化量,最后再dfs一次换根就行了

复杂度O(n*log(n))。不过考场上我没有想到如何用树状数组解决这个问题,在dfs序上开了一棵主席树

复杂度也是O(nlog(n))的,不过常数比较大,再加上那个OJ比较慢,最后只有90分

主席树写法:

#include<bits/stdc++.h>
using namespace std;
inline 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<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int maxn=1e6+5;
struct edge{int to,nxt;}e[maxn<<1];
int head[maxn],num,w[maxn],lsh[maxn],ext,n;
inline void add(int x,int y)
{
e[++num]=(edge){y,head[x]};head[x]=num;
e[++num]=(edge){x,head[y]};head[y]=num;
}
struct szsz{
#define lowbit(x) (x&(-x))
int c[maxn];
inline int query(int x){int res=0;for(;x;x-=lowbit(x))res+=c[x];return res;}
inline void update(int x,int val){for(;x<=ext;x+=lowbit(x))c[x]+=val;}
}z;
int dfn[maxn],pp[maxn],cnt,siz[maxn];
long long ans[maxn];
inline void dfs1(int x,int f)
{
ans[1]=ans[1]+z.query(ext)-z.query(w[x]);
z.update(w[x],1);siz[x]=1;
dfn[x]=++cnt;pp[cnt]=x;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(y==f)continue;
dfs1(y,x); siz[x]+=siz[y];
} z.update(w[x],-1);
}
struct hjts{
int sum[maxn*23],root[maxn],cnt,ls[maxn*23],rs[maxn*23];
inline void update(int &rt1,int rt2,int l,int r,int pos)
{
rt1=++cnt; sum[rt1]=sum[rt2];
++sum[rt1]; if(l==r)return ;
ls[rt1]=ls[rt2];rs[rt1]=rs[rt2];
int mid=(l+r)>>1;
if(pos<=mid) update(ls[rt1],ls[rt2],l,mid,pos);
else update(rs[rt1],rs[rt2],mid+1,r,pos);
sum[rt1]=sum[ls[rt1]]+sum[rs[rt1]];
}
inline int query(int rt,int rt2,int l,int r,int ll,int rr)
{
if(ll>rr||rt==rt2)return 0;
if(l>=ll&&r<=rr) return sum[rt]-sum[rt2];
int mid=(l+r)>>1,res=0;
if(ll<=mid) res+=query(ls[rt],ls[rt2],l,mid,ll,rr);
if(rr>mid) res+=query(rs[rt],rs[rt2],mid+1,r,ll,rr);
return res;
}
inline int getval(int l,int r,int ll,int rr)
{
if(l>r||ll>rr)return 0;
return query(root[r],root[l-1],1,ext,ll,rr);
}
}tr;
inline void dfs2(int x,int f)
{
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to; if(y==f)continue;
int tmp1=tr.getval(1,dfn[y]-1,1,w[y]-1)+tr.getval(dfn[y]+siz[y],n,1,w[y]-1);
int tmp2=tr.getval(dfn[y],dfn[y]+siz[y]-1,1,w[x]-1);
ans[y]=ans[x]+tmp1-tmp2; dfs2(y,x);
}
}
signed main()
{
freopen("tears.in","r",stdin);
freopen("tears.out","w",stdout);
n=read();int q=read();
for(int i=1;i<=n;i++)
{
w[i]=read();
lsh[++ext]=w[i];
}
for(int i=1;i<n;i++)add(read(),read());
sort(lsh+1,lsh+1+ext);
ext=unique(lsh+1,lsh+1+ext)-lsh-1;
for(int i=1;i<=n;i++)w[i]=lower_bound(lsh+1,lsh+1+ext,w[i])-lsh;
dfs1(1,0);for(int i=1;i<=n;i++)
tr.update(tr.root[i],tr.root[i-1],1,ext,w[pp[i]]);
dfs2(1,0);int x; for(int i=1;i<=q;i++)
x=read(),printf("%lld\n",ans[x]);
}

树状数组写法:

#include<bits/stdc++.h>
using namespace std;
inline 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<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int maxn=1e6+5;
struct edge{int to,nxt;}e[maxn<<1];
int head[maxn],num,w[maxn],lsh[maxn],ext,n;
inline void add(int x,int y)
{
e[++num]=(edge){y,head[x]};head[x]=num;
e[++num]=(edge){x,head[y]};head[y]=num;
}
struct szsz{
#define lowbit(x) (x&(-x))
int c[maxn];
inline int query(int x){int res=0;for(;x;x-=lowbit(x))res+=c[x];return res;}
inline void update(int x,int val){for(;x<=ext;x+=lowbit(x))c[x]+=val;}
}z;
int dfn[maxn],pp[maxn],sum1[maxn],sum2[maxn],cnt,siz[maxn];
long long ans[maxn];
inline void dfs1(int x,int f)
{
z.update(w[x],1);siz[x]=1;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(y==f)continue;
int jb=z.query(w[x]-1);
int bj=z.query(w[y]-1);
dfs1(y,x);
sum2[y]=z.query(w[y]-1)-bj;
sum1[y]=z.query(w[x]-1)-jb;
ans[1]+=sum2[y];
}
if(x==1)ans[1]+=z.query(w[1]-1);
}
inline void dfs2(int x,int f)
{
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to; if(y==f)continue;
ans[y]=ans[x]-sum1[y]+z.query(w[y]-1)-sum2[y];
dfs2(y,x);
}
}
signed main()
{
freopen("tears.in","r",stdin);
freopen("tears.out","w",stdout);
n=read();int q=read();
for(int i=1;i<=n;i++)
{
w[i]=read();
lsh[++ext]=w[i];
}
for(int i=1;i<n;i++)add(read(),read());
sort(lsh+1,lsh+1+ext);
ext=unique(lsh+1,lsh+1+ext)-lsh-1;
for(int i=1;i<=n;i++)w[i]=lower_bound(lsh+1,lsh+1+ext,w[i])-lsh;
dfs1(1,0); dfs2(1,0);
int x; for(int i=1;i<=q;i++)
x=read(),printf("%lld\n",ans[x]);
}

T3 传统异能

这个题挺不错的,由于我自己之前只会O(n)求不同子序列个数的写法,所以没有想到可以用矩阵;

先说一下n^2的做法,我们可以设dp[i][1/0] 为第i个字符选或者不选的能够构成的子序列的个数

lst[c]为c这个字符上一次出现的位置,那么转移的话就是:

dp[i][1]=(dp[i-1][1]+dp[i-1][0]+1)%mod;
dp[i][0]=(dp[i-1][1]+dp[i-1][0])%mod;
if(lst[a[i]]) dp[i][0]=(dp[i][0]+mod-dp[lst[a[i]]][1])%mod;

当然,如果你写了这个式子之后就会很难想到正解,因为这个式子有减去的地方,会很难处理

所以我们就要用一种复杂度稍微高一些的做法来想到正解

我们设dp[i][j]为前i个字符里面,以j结尾的子序列有多少个,

那么转移的话就是

if(j==s[i]) dp[i][j]=dp[i][1]+dp[i][2]+dp[i][3]+1;
else dp[i][j]=dp[i-1][j];

我觉得还是比较好理解的,我们假如让所有的以c为结尾的子序列再加上一个c

那么现在以c结尾的子序列的最小长度都为2,那么再加上让以a和b结尾的子序列加一个c

就又补回来了,最后再加1表示前面一个都不被选择,只选它自己

我们发现这是一个很明显的矩形式子,因为字符集大小只有3,所以我们可以构建三个不同的矩阵

第1个矩阵大概长这个亚子

1 0 0 0
1 1 1 1
0 0 1 0
0 0 0 1

对角线显然都是1,然后第i行是1,嗯就这样

然后我们可以用线段树维护一下每个点对应的矩形,以及区间乘积是多少 相信大家都知道矩形支持交换律

查询完之后再让答案矩形乘一个这个矩阵

1 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0

将第一列的加起来就是答案了

#include<bits/stdc++.h>
#define int long long
#define lid id<<1
#define rid id<<1|1
using namespace std;
inline 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<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int mod=998244353;
const int maxn=1e5+5;
struct matrix{
int mat[5][5];
inline void init(){
memset(mat,0,sizeof(mat));
for(int i=0;i<=3;i++)mat[i][i]=1;
}
inline void clear(){memset(mat,0,sizeof(mat));}
inline void print()
{
for(int i=0;i<=3;i++)
{
for(int j=0;j<=3;j++)
cout<<mat[i][j]<<" ";
cout<<endl;
}
}
inline matrix operator*(const matrix &a)const{
matrix c;c.clear();
for(int i=0;i<=3;i++) for(int j=0;j<=3;j++) for(int k=0;k<=3;k++)
(c.mat[i][j]=a.mat[i][k]*mat[k][j]%mod+c.mat[i][j])%=mod;
return c;
}
}tmp[4];
int n,m;
inline int id(char c){return c-'A'+1;}
char s[maxn];int a[maxn];
matrix sum[maxn<<2];
inline void init()
{
tmp[1].init();tmp[2].init();tmp[3].init();
for(int i=1;i<=3;i++) for(int j=0;j<=3;j++)
tmp[i].mat[i][j]=1;tmp[0].clear();
tmp[0].mat[0][0]=1;
}
inline void build(int id,int l,int r)
{
if(l==r) return sum[id]=tmp[a[l]],void();
int mid=(l+r)>>1;
build(lid,l,mid);build(rid,mid+1,r);
sum[id]=sum[lid]*sum[rid];
}
inline void update(int id,int l,int r,int pos)
{
if(l==r) return sum[id]=tmp[a[pos]],void();
int mid=(l+r)>>1;
if(pos<=mid) update(lid,l,mid,pos);
else update(rid,mid+1,r,pos);
sum[id]=sum[lid]*sum[rid];
}
inline matrix query(int id,int l,int r,int ll,int rr)
{
if(l>=ll&&r<=rr)return sum[id];
int mid=(l+r)>>1;matrix a;a.init();
if(ll<=mid) a=query(lid,l,mid,ll,rr);
if(rr>mid) a=a*query(rid,mid+1,r,ll,rr);
return a;
}
signed main()
{
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
n=read();m=read(); scanf("%s",s+1);
for(int i=1;i<=n;i++) a[i]=id(s[i]);
init();build(1,1,n);
while(m--)
{
int type=read();
if(type==2)
{
int ll=read(),rr=read();
matrix ans=query(1,1,n,ll,rr);
ans=tmp[0]*ans;int sum=0;
sum=(ans.mat[1][0]+ans.mat[2][0]+ans.mat[3][0])%mod;
printf("%lld\n",sum);
}
else
{
int pos=read();char c;cin>>c;
a[pos]=id(c);update(1,1,n,pos);
}
}
}

T4 铺设道路

我们假设第0块和第n+1块的高度为0,那么显然此时的答案不会改变

那么,我们首先可以先将其差分一下,我们将每个点的高度干到0,等价于将差分数组全部干到0

对于i>=1&&i<=n来说 我们设b[i]为d[i]-d[i-1],即差分数组

那么显然最短时间就是sigma(max(b[i],0));

对于b[l]和b[r],假设我们对l到r-1(r>l)之间施一次工,那么b[l]会-1,b[r]会+1

那么我们考虑一个贪心思想,如果我们想要总体力是最大的,那么我们应该让每个小于0的b[r]匹配的b[l]越远越好

最小的则反之,我们从1枚举每个b[i],如果b[i]>0就将其压入队列,否则就取队尾或者队首进行操作

复杂度O(n);

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline 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<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int mod=1e9+7;
const int maxn=3e5+5;
int n,d[maxn],b[maxn];
deque<int >q;
signed main()
{
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
n=read();int ans=0;
for(int i=1;i<=n;i++)
{
d[i]=read();b[i]=d[i]-d[i-1];
ans+=max(0ll,d[i]-d[i-1]);
}
printf("%lld\n",ans);
int maxx=0,minn=0;n++;b[n]=-d[n-1];
for(int i=1;i<=n;i++)
{
if(b[i]>0) q.push_back(i);
else while(b[i])
{
int x=q.back();
if(abs(b[i])>=abs(b[x]))
{
q.pop_back();
(maxx+=(i-x)*(i-x)%mod*b[x]%mod)%=mod;
b[i]+=b[x];b[x]=0;
}
else
{
(maxx+=(i-x)*(i-x)%mod*(-b[i])%mod)%=mod;
b[x]+=b[i];b[i]=0;
}
}
}
for(int i=1;i<=n;i++) b[i]=d[i]-d[i-1];
printf("%lld\n",maxx);
for(int i=1;i<=n;i++)
{
if(b[i]>0) q.push_back(i);
else while(b[i])
{
int x=q.front();
if(abs(b[i])>=abs(b[x]))
{
q.pop_front();
(minn+=(i-x)*(i-x)%mod*b[x]%mod)%=mod;
b[i]+=b[x];b[x]=0;
}
else
{
(minn+=(i-x)*(i-x)%mod*(-b[i])%mod)%=mod;
b[x]+=b[i];b[i]=0;
}
}
}
printf("%lld\n",minn);
}

总结::

距离noip2021不远了,csp的失利一直缠绕再我心头,不过我是不会放弃的,加油吧JYF!!!!!!!

冲刺noip2021模拟16的更多相关文章

  1. 2021.10.26考试总结[冲刺NOIP模拟16]

    T1 树上的数 \(DFS\)一遍.结构体存边好像更快? \(code:\) T1 #include<bits/stdc++.h> using namespace std; namespa ...

  2. 【CJOJ P1957】【NOIP2010冲刺十模拟赛】数字积木

    [NOIP2010冲刺十模拟赛]数字积木 Description 小明有一款新式积木,每个积木上都有一个数,一天小明突发奇想,要是把所有的积木排成一排,所形成的数目最大是多少呢? 你的任务就是读入n个 ...

  3. 2021.7.15考试总结[NOIP模拟16]

    ZJ模拟D2就是NB.. T1 Star Way To Heaven 谁能想到这竟是个最小生成树呢?(T1挂分100的高人JYF就在我身边 把上边界和下边界看成一个点和星星跑最小生成树,从上边界开始跑 ...

  4. 冲刺Noip2017模拟赛8 解题报告——五十岚芒果酱

    1.鼎纹 [问题描述] 据说鼎纹的 种制造 式是 铜模印出来的,这是我国古代劳动 智慧 的结晶.铜模印过的地 ,会留下深深的印记,经过时间的炼化,洗 练成历史的遗存. 聪明的古代劳动人民拥有一个 a ...

  5. 冲刺Noip2017模拟赛7 解题报告——五十岚芒果酱

    1.二叉树(binary) .二叉树 (binary.cpp/c/pas) [问题描述] 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: ()若左子树不空,则左子树上所有结点的值均小于它的根结 ...

  6. 冲刺Noip2017模拟赛4 解题报告——五十岚芒果酱

    题1 韬韬抢苹果(apple) [问题描述] 又到了收获的季节,树上结了许多韬韬,错了,是许多苹果,有很多个小韬韬都来摘苹 果.每个韬韬都想要最大的苹果,所以发生了争执,为了解决他们的矛盾,出题人定了 ...

  7. 冲刺Noip2017模拟赛2 解题报告——五十岚芒果酱

    题1 牛跑步(running) [题目描述] 新牛到部队,CG 要求它们每天早上搞晨跑,从 A 农场跑到 B 农场.从 A 农场到 B 农场中有 n- 个路口,分别标上号,A 农场为 号,B 农场为 ...

  8. 冲刺Noip2017模拟赛1 解题报告——五十岚芒果酱

    题1 国际象棋(chess) [问题描述] 有N个人要参加国际象棋比赛,该比赛要进行K场对弈.每个人最多参加2场对弈,最少参加0场对弈.每个人都有一个与其他人都不相同的等级(用一个正整数来表示).在对 ...

  9. 7.15考试总结(NOIP模拟16)[Star Way To Heaven·God Knows·Lost My Music]

    败者死于绝望,胜者死于渴望. 前言 一看这个题就来者不善,对于第一题第一眼以为是一个大模拟,没想到是最小生成树. 对于第二题,先是看到了状压可以搞到的 20pts 然后对着暴力一顿猛调后来发现是题面理 ...

随机推荐

  1. 掌握基于AOP事务管理

    一.手动管理和半自动工厂模式 二.AOP事务管理 1.表达式中,第一个※是返回值所有类型,service包下一个点意思是service包下的类,两个点意思是service包下的类和其子包下的类也包含, ...

  2. Vue开发多人聊天室 复盘总结

    前言 在上个月初,接到一个需求,要开发一个 聊天通讯 模块 并且 集成到 项目中的多个 入口,实现业务数据的记录追踪. 接到需求后,还挺开心,这是我第一次 搞 通讯 类的需求,之前一直是 B 端 的业 ...

  3. 【第一篇】- Git 教程之Spring Cloud直播商城 b2b2c电子商务技术总结

    Git 教程 Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目. Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制 ...

  4. Java-枚举(Enum)

    1.枚举概述 枚举是一个被命名的整型常数的集合,用于声明一组带标识符的常熟.当一个变量有几种固定可能的取值时,就可以将其定义为枚举类型. 1.1 声明枚举 Java中枚举是一个特殊的类,使用enum关 ...

  5. 解读Flex布局及其基本使用

    Flex布局的基本内容: felx布局意为"弹性布局",主要用于为盒状模型提供最大的灵活性.被广泛的应用于移动端,PC端的响应式布局. 首先:定义盒子为flex布局: .box{ ...

  6. Loadrunner拼装唯一值方法

    由于Loadrunner函数有限性,唯一值需要几个函数的字符串进行拼装,可实现流水号.订单号等等数值的唯一性.具体可见下列方法: 方法一: char OraderID[15];srand(time{N ...

  7. Sentry 监控 - Search 搜索查询实战

    系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创建版本 快速使用 Docker 上手 Sentry-CLI - 30 秒上手 Source Maps Sentry For ...

  8. shell脚本在CentOS7自动更包

    手动更包有些繁琐,就想着用脚本自动更包,后来试了下,最后成功啦! 以下是根据实际项目编写的: 操作环境:centos7.0 tomcat版本:7.0.78 以下为项目存放目录如下: updatefil ...

  9. 鸿蒙内核源码分析(调度故事篇) | 用故事说内核调度 | 百篇博客分析OpenHarmony源码 | v9.07

    百篇博客系列篇.本篇为: v09.xx 鸿蒙内核源码分析(调度故事篇) | 用故事说内核调度过程 | 51.c.h .o 前因后果相关篇为: v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 ...

  10. Kettle学习笔记(一)— 环境部署及运行

    目录 Kettle学习笔记(一)-环境部署及运行 Kettle学习笔记(二)- 基本操作 kettle学习笔记(三)- 定时任务的脚本执行 Kettle学习笔记(四)- 总结 Kettle简介 Ket ...