NOIP模拟90(多校23)
T1 回文
解题思路
原来 \(n^3\) 可以过 500 。。。
先枚举一下路径长度,对于同一路径长度点数最多是 \(n\) 个,我们可以接着枚举从 \((n,m)\) 出发的路径长度相同的点。
然后对于字母相同的位置向下一层转移。
DP 数组可以只开三维 \(f_{i,j,k}\) 表示从 \((1,1)\) 出发到达 \((i,j)\) 点,从 \((n,m)\) 出发的点目前横坐标与出发点差值是 \(k\) 。
由于路径相同因此我们也可以确定对应的纵坐标,代码实现不难,但是有一点卡常。
code
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){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 N=510,M=90,mod=993244853;
int n,m,len,ans,f[N][N][N];
int d1[10]={0,-1,0,-1,0};
int d2[10]={0,0,-1,0,-1};
int d3[10]={0,1,1,0,0};
int d4[10]={0,0,0,1,1};
vector< pair<int,int> > p[N<<1][30],q[N<<1][30];
char s[N][N];
#define add(x,y) {x+=y;if(x>=mod)x-=mod;}
int main()
{
freopen("palin.in","r",stdin); freopen("palin.out","w",stdout);
n=read(); m=read(); len=(n+m-1)>>1;
for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(i+j-1<=len) p[i+j-1][s[i][j]-'a'].push_back(make_pair(i,j));
else q[(n-i+1)+(m-j+1)-1][s[i][j]-'a'].push_back(make_pair(i,j));
if(s[1][1]!=s[n][m]) printf("0"),exit(0);
f[1][1][n]=1;
for(int l=1;l<=len;l++)
for(int col=0;col<26;col++)
for(auto it1:p[l][col])
for(auto it2:q[l][col])
for(int k=1;k<=4;k++)
{
int i=it1.first,j=it1.second,x=it2.first,y=it2.second;
int ni=i+d3[k],nj=j+d4[k],nx=x+d1[k],ny=y+d2[k];
if(s[ni][nj]==s[nx][ny]) add(f[ni][nj][nx],f[i][j][x]);
}
if((n+m-1)&1)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if((i+j-1)==len+1)
for(int k=1;k<=4;k++)
add(ans,f[i+d1[k]][j+d2[k]][i+d3[k]]);
}
else
{
for(int col=0;col<26;col++)
for(auto it:p[len][col])
{
int i=it.first,j=it.second;
for(int k=2;k<=3;k++)
{
int x=i+d3[k],y=j+d4[k];
add(ans,f[i][j][x]);
}
}
}
printf("%d",ans);
return 0;
}
T2 快速排序
解题思路
发现其实题目给的是对于操作区间的第一个数字为基准进行的快速排序。
那么如果第一个数字是 \(nan\) 的话,显然这次操作不会改变序列中任何一个数字的位置。
那么如果第一个数字不是 \(nan\) 的话,就是把它后面所有小于它的数字都放到它前面,其余的东西照常做就好了。
可以用 multiset
维护或者排序一遍直接指针扫。
code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){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 N=5e5+10;
int T,n,cnt,ans[N];
struct Node{bool jud;int val;}s[N];
multiset< pair<int,int> > res;
bool vis[N];
bool operator < (const Node& x, const Node& y)
{
if(x.jud || y.jud)
return false;
return x.val < y.val;
}
void solve()
{
n=read(); cnt=0; string ch;
for(int i=1;i<=n;i++)
{
cin>>ch; vis[i]=false; if(ch[0]=='n'){s[i].jud=true;continue;}
int x=0; for(int j=0;j<ch.size();j++) x=(x<<1)+(x<<3)+(ch[j]^48);
s[i].jud=false; s[i].val=x; res.insert(make_pair(s[i].val,i));
}
for(int i=1;i<=n;i++)
{
if(vis[i]) continue;
if(s[i].jud){ans[++cnt]=-1;continue;}
while((*res.begin()).first<s[i].val)
{
ans[++cnt]=(*res.begin()).first;
vis[(*res.begin()).second]=true; res.erase(res.begin());
}
ans[++cnt]=(*res.begin()).first;
vis[(*res.begin()).second]=true; res.erase(res.begin());
}
for(int i=1;i<=n;i++) if(ans[i]==-1) printf("nan ");else printf("%lld ",ans[i]);
putchar('\n');
}
#undef int
int main()
{
#define int long long
freopen("qsort.in","r",stdin); freopen("qsort.out","w",stdout);
T=read(); while(T--) solve();
return 0;
}
T3 混乱邪恶
解题思路
好像是一道高联题,然而我并不是特别会证明。
肯定是要先排序的,那么先让 \(2i\) 和 \(2i-1\) 分到不同的组,两个的差值记为 \(d_i\) 。
然后对于所有的 \(d\) 进行排序选择最大的与最小的相减,将差值计入集合,相当于是把较小值所代表的集合的符号进行了更改。
最后 DFS 一遍输出答案就好了。
code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){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 N=2e6+10;
int n,m,cnt,id,all,d[N],ans[N];
struct Node{int id,dat;}s[N];
vector< pair<int,int> > v[N];
multiset< pair<int,int> > res;
bool comp(Node x,Node y){if(x.dat!=y.dat)return x.dat<y.dat;return x.id<y.id;}
void dfs(int x,int flag)
{
if(!v[x].size()) return ans[s[x].id]=flag,void();
for(auto it:v[x])
dfs(it.first,flag*it.second);
}
#undef int
int main()
{
#define int long long
freopen("chaoticevil.in","r",stdin); freopen("chaoticevil.out","w",stdout);
cnt=n=read(); m=read(); printf("NP-Hard solved\n");
for(int i=1;i<=n;i++) s[i].dat=read(),s[i].id=i; if(n&1) n++;
sort(s+1,s+n+1,comp); id=n;
for(int i=1;i<=n/2;i++)
all+=(s[2*i].dat-s[2*i-1].dat!=1),id++,v[id].push_back(make_pair(2*i-1,-1)),
v[id].push_back(make_pair(2*i,1)),res.insert(make_pair(s[2*i].dat-s[2*i-1].dat,id));
while(all)
{
auto t1=*res.begin(),t2=*res.rbegin();
all-=(t1.first!=1)+(t2.first!=1); all+=(t2.first-t1.first!=1);
pair<int,int> temp=make_pair(t2.first-t1.first,++id);
v[id].push_back(make_pair(t1.second,-1)); v[id].push_back(make_pair(t2.second,1));
res.erase(res.find(t1)); res.erase(res.find(t2)); res.insert(temp);
}
int flag=1; for(auto it:res) dfs(it.second,flag),flag=-flag;
for(int i=1;i<=cnt;i++) printf("%lld ",ans[i]);
return 0;
}
T4 校门外歪脖树上的鸽子
解题思路
把 \([l,r]\) 区间上的修改视为 \(l-1\) 以及 \(r+1\) 这两个点所连接的整个路径。
开两颗线段树维护,对于左边的这条链每一次给对应父亲节点的右子树加入贡献,右边的这条链则相反。
对于询问操作也是类似的进行查询。
code
#include<bits/stdc++.h>
#define int long long
#define ls x<<1
#define rs x<<1|1
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){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 N=4e5+10;
int n,m,root,tim,dfn[N],siz[N],son[N],topp[N],fa[N],dep[N],id[N],ch[N][2],vis[N];
struct Segment_tree
{
int bas[N];
struct Node{int l,r,dat,laz,siz;}tre[N<<2];
inline void add(int x,int val){tre[x].dat+=val*tre[x].siz;tre[x].laz+=val;}
#define push_up(x) tre[x].dat=tre[ls].dat+tre[rs].dat
#define push_down(x) add(ls,tre[x].laz),add(rs,tre[x].laz),tre[x].laz=0
void build(int x,int l,int r)
{
if(l==r) return tre[x].siz=bas[l],void();
int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r);
push_up(x); tre[x].siz=tre[ls].siz+tre[rs].siz;
}
void insert(int x,int l,int r,int L,int R,int val)
{
if(L>R) return ;
if(L<=l&&r<=R) return add(x,val),void();
int mid=(l+r)>>1; if(tre[x].laz) push_down(x);
if(L<=mid) insert(ls,l,mid,L,R,val);
if(R>mid) insert(rs,mid+1,r,L,R,val);
push_up(x);
}
int query(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return tre[x].dat;
int mid=(l+r)>>1,sum=0; if(tre[x].laz) push_down(x);
if(L<=mid) sum+=query(ls,l,mid,L,R);
if(R>mid) sum+=query(rs,mid+1,r,L,R);
return sum;
}
}L,R;
void dfs1(int x)
{
if(!ch[x][0]&&!ch[x][1]) siz[x]=1;
for(int i=0;i<=1;i++)
{
int to=ch[x][i]; if(!to) continue;
fa[to]=x; dep[to]=dep[x]+1; dfs1(to);
siz[x]+=siz[to]; if(siz[son[x]]<siz[to]) son[x]=to;
}
}
void dfs2(int x,int tp)
{
topp[x]=tp; dfn[x]=++tim;
if(son[x]) dfs2(son[x],tp);
for(int i=0;i<=1;i++)
if(ch[x][i]&&!dfn[ch[x][i]])
dfs2(ch[x][i],ch[x][i]);
R.bas[dfn[ch[x][1]]]=siz[ch[x][0]];
L.bas[dfn[ch[x][0]]]=siz[ch[x][1]];
}
void update(int x,int y,int val)
{
x=id[x-1]; y=id[y+1]; int lasx=x,lasy=y;
while(topp[x]^topp[y])
if(dep[topp[x]]<dep[topp[y]])
R.insert(1,1,tim,dfn[topp[y]],dfn[y],val),lasy=topp[y],y=fa[topp[y]];
else L.insert(1,1,tim,dfn[topp[x]],dfn[x],val),lasx=topp[x],x=fa[topp[x]];
if(dep[x]<dep[y]) R.insert(1,1,tim,dfn[x]+2,dfn[y],val),L.insert(1,1,tim,dfn[lasx],dfn[lasx],-val);
else L.insert(1,1,tim,dfn[y]+2,dfn[x],val),R.insert(1,1,tim,dfn[lasy],dfn[lasy],-val);
}
int query(int x,int y)
{
x=id[x-1]; y=id[y+1]; int lasx=x,lasy=y,sum=0;
while(topp[x]^topp[y])
if(dep[topp[x]]<dep[topp[y]])
sum+=R.query(1,1,tim,dfn[topp[y]],dfn[y]),lasy=topp[y],y=fa[topp[y]];
else sum+=L.query(1,1,tim,dfn[topp[x]],dfn[x]),lasx=topp[x],x=fa[topp[x]];
if(dep[x]<dep[y]) sum+=R.query(1,1,tim,dfn[x]+2,dfn[y])-L.query(1,1,tim,dfn[lasx],dfn[lasx]);
else sum+=L.query(1,1,tim,dfn[y]+2,dfn[x])-R.query(1,1,tim,dfn[lasy],dfn[lasy]);
return sum;
}
#undef int
int main()
{
#define int long long
freopen("pigeons.in","r",stdin); freopen("pigeons.out","w",stdout);
int opt,x,y,z; n=read(); m=read();
for(int i=1;i<n;i++) vis[ch[i+n][0]=read()]=true,vis[ch[i+n][1]=read()]=true;
for(int i=1;i<=2*n;i++) if(!vis[i]){root=i;break;}
ch[2*n+1][0]=2*n; ch[2*n+1][1]=root; ch[2*n+3][0]=2*n+1; ch[2*n+3][1]=2*n+2;
for(int i=1;i<=n;i++) id[i]=i; id[0]=2*n; id[n+1]=2*n+2; root=2*n+3;
dfs1(root); dfs2(root,root); L.build(1,1,tim); R.build(1,1,tim);
while(m--){opt=read(); x=read(); y=read();if(opt==1) z=read(),update(x,y,z);else printf("%lld\n",query(x,y));}
return 0;
}
NOIP模拟90(多校23)的更多相关文章
- NOIP模拟83(多校16)
前言 CSP之后第一次模拟赛,感觉考的一般. 不得不吐槽多校联测 OJ 上的评测机是真的慢... T1 树上的数 解题思路 感觉自己思维有些固化了,一看题目就感觉是线段树. 考完之后才想起来这玩意直接 ...
- Noip模拟46 2021.8.23
给了签到题,但除了签到题其他的什么也不会.... T1 数数 人均$AC$,没什么好说的,就是排个序,然后双指针交换着往中间移 1 #include<bits/stdc++.h> 2 #d ...
- NOIP模拟84(多校17)
T1 宝藏 解题思路 考场上一眼出 \(nlog^2\) 做法,然后没看见是 1s 3e5 的数据,我竟然以为自己切了?? 考完之后尝试着把二分改为指针的移动,然后就过了??或许是数据水吧,感觉自己的 ...
- NOIP模拟92(多校25)
前言 所以说这次是 HZOI 多校联测巅峰????(题目,数据过水??) T1 石子合并 解题思路 签到题. 发现我们可以给每个数字附一个正负号,每个数字的贡献就是它本身乘上这个符号. 发现至少应该有 ...
- NOIP模拟85(多校18)
前言 好像每个题目背景所描述的人都是某部番里的角色,热切好像都挺惨的(情感上的惨). 然后我只知道 T1 的莓,确实挺惨... T1 莓良心 解题思路 首先答案只与 \(w\) 的和有关系,于是问题就 ...
- NOIP模拟86(多校19)
T1 特殊字符串 解题思路 \(f_{i,j}\) 表示前 \(i\) 个字符中结尾为 \(j\) 的最大贡献. 转移枚举当前位置于之前位置结尾的组合加上贡献即可. 对于边界问题,容易发现选择 1 一 ...
- NOIP模拟88(多校21)
前言 对于这套题的总体感觉就是难,然后就是自己很菜... 对于 T1 考试时只会一个最垃圾的背包,考完之后对于思路这一块也不是很顺利,大概这就是薄弱的地方吧. 然后 T2 是比较简单的一道题了,但是考 ...
- NOIP模拟96(多校29)
T1 子集和 解题思路 大概是一个退背包的大白板,然而我考场上想复杂了,竟然还用到了组合数. 但是大概意思是一样的,有数的最小值一定是一个在 \(a\) 数组中存在的数字. 那么我们想办法除去它对应的 ...
- NOIP模拟99(多校31)
T1 法阵 解题思路 原题3100,张口放 T1(出题人原话) 思维题,合法的情况其实就是上下两个梯形拼起来的样子. 他们的边界都是在 \(i\) 轴上面,但是不能相交. 于是我们可以尝试两者相交的纵 ...
- 5.23考试总结(NOIP模拟2)
5.23考试总结(NOIP模拟2) 洛谷题单 看第一题第一眼,不好打呀;看第一题样例又一眼,诶,我直接一手小阶乘走人 然后就急忙去干T2T3了 后来考完一看,只有\(T1\)骗到了\(15pts\)[ ...
随机推荐
- 整理k8s————k8s组件[二]
前言 简单整理一下k8s 组件. 正文 borg 架构: borgmaster 是处理请求分发的. borglet 是具体运行容器. 这里有一个调度scheduler,这个比较重要吧. 比如说用户通过 ...
- sql 语句系列(闰年)[八百章之第十九章]
前言 判断闰年还是挺有用的. mysql select DAY(LAST_DAY(DATE_ADD(CURRENT_DATE,INTERVAL -DAYOFYEAR(CURRENT_DATE)+1+3 ...
- redis 简单整理——客户端通信协议[十五]
前言 简单介绍一下客户端的通信协议. 正文 第 一,客户端与服务端之间的通信协议是在TCP协议之上构建的. 第二, Redis制定了RESP(REdis Serialization Protocol, ...
- 重新点亮linux 命令树————文件特殊权限[十一]
前言 简单介绍一下文件特殊权限. 正文 SUID 用于二进制可执行文件,执行命令时取得文件属组权限 如 /usr/bin/passwd 当我们使用passwd 修改密码的时候其实是以root用户身份进 ...
- oracle 数据库连接
前言 关于oracle 数据库如何连接,我一开始以为和mysql 和 sql server一样,写好连接语句然后调用相应的dll. 知道我遇到了两个错误: 1.64位程序不能去驱动32位客户端 2.O ...
- aop 阶段性概况
前言 对aop进行一个阶段性的总结. 正文 首先什么是aop呢? 那么首先看aop的解决什么样的问题. public class Program { public static void Main(s ...
- 单点登录(SSO)实现详解!!!
单点登录是什么?你是怎么理解的?单点登录是如何实现的 普通登录 提到单点登录,首先可以想到传统登录,通过登录页面根据用户名查询用户信息,判断密码是否正确,正确则将用户信息写到session,访问的时候 ...
- 写给大家看的“不负责任” K8s 入门文档
前言 2019 年下半年,我做了一次转岗,开始接触到 Kubernetes,虽然对 K8s 的认识还非常的不全面,但是非常想分享一下自己的一些收获,希望通过本文能够帮助大家对 K8s 有一个入门的了解 ...
- 如何合理使用 CPU 管理策略,提升容器性能?
简介:CPU Burst.拓扑感知调度是阿里云容器服务 ACK 提升应用性能的两大利器,它们解决了不同场景下的 CPU 资源管理,可以共同使用.点击下文,查看详情! 作者:张佐玮(佑祎) 前言 在云 ...
- 深入理解 C++ 中的多态与文件操作
C++ 多态 多态(Polymorphism)是面向对象编程(OOP)的核心概念之一,它允许对象在相同操作下表现出不同的行为.在 C++ 中,多态通常通过继承和虚函数来实现. 理解多态 想象一个场景, ...