[NOIP模拟13]题解
A.矩阵游戏
其实挺水的?
考场上根本没有管出题人的疯狂暗示(诶这出题人有毛病吧这么简单的东西写一大堆柿子),而且推公式能力近乎没有,所以死掉了。
很显然乘法有交换率结合率所以操作顺序对最终结果没什么影响对吧,垃圾如我都能一眼看出来。
统计一下每行总共乘的倍数$h_i$,每列总共乘的倍数$l_i$,
之后考虑$O(n^2)$怎么求出答案:$ans=\sum \limits _{i=1}^{n}h_i \sum \limits _{j=1}^{m}l_j\times((i-1)\times m+j)$
化简一下:$\sum \limits_{i=1}^{n}h_i \sum \limits_{j=1}^{m} l_j\times (i-1)\times m+l_j\times j$
继续:$\sum h_i\sum l_j\times j + \sum h_i \times (i-1)\times m \sum l_j$
显然可以$O(n)$了吧
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll mod=1e9+;
const int N=,M=;
int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<='')x=x*+ch-'',ch=getchar();
return x*f;
}
int n,m,K;
ll hang[N],lie[N],sum,ans;
int toth,totl; int main()
{
n=read();m=read();K=read();
for(int i=;i<=n;i++)hang[i]=;
for(int i=;i<=m;i++)lie[i]=;
char str[];
for(int i=;i<=K;i++)
{
scanf("%s",str);
if(str[]=='R')
{
int num=read();ll val=1LL*read();
(hang[num]*=val)%=mod;
}
else
{
int num=read();ll val=1LL*read();
(lie[num]*=val)%=mod;
}
}
ll sumhang=,ans=;
for(int i=;i<=n;i++)
{
ll now=1LL*(i-)*m+;
now%=mod;
sum+=now*hang[i]%mod,sum%=mod;
sumhang+=hang[i],sumhang%=mod; }
for(int i=;i<=m;i++)
{
ans+=sum*lie[i]%mod,ans%=mod;
sum+=sumhang,sum%=mod;
}
cout<<ans<<endl;
return ;
}
B.跳房子
RT,跳楼题
我这样的菜b就只能想到大模拟,然而大佬就是能想出来线段树+置换群+快速幂的做法。
(我就是没脸我就要粘blog)
关于代码实现,说几点细节。
可以让$a[0][j]=a[n][j],a[n+1][j]=a[1][j]$,这样写找下一步的函数就比较简单,修改的时候特判一下就好。
置换的运算:$res[i]=b[a[i]]$,可以直接丢到快速幂里跑实现倍增的效果。
询问的时候暴力部分记得分类全,考虑它是否能越界。
query函数如果直接把映射当参传的话记得取地址。
C.优美序列
部分分还是很多而且比较好拿的,由于值域范围比较友好我们可以记录一下每个编号对应的位置$pos[]$,然后用数据结构分别维护$a[]$和$pos[]$序列上的最大最小值。之后对于每个询问$[l,r]$,先查询$[l,r]$的编号最大最小值,然后就得到了一段值域,再在这段值域上查询位置的最左和最右端点。如果最左和最右端点都在$[l,r]$内(事实上,只有可能查出来就是$[l,r]$,在它之内是不可能的),那么$[l,r]$即为所求。否则,将新得到的最左最右端点作为新的$l$和$r$再次询问。重复这个过程,最后一定能得到解。
这种办法考场上就已经码出来了,后来又分别用线段树和ST表实现了一下。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=; const int L=<<|;
char buffer[L],*S,*T;
#define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++) int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<='')x=x*+ch-'',ch=getchar();
return x*f;
}
int a[N],n,m,pos[N];
#define ls(k) k<<1
#define rs(k) k<<1|1
int maxx[N<<],minn[N<<],pmax[N<<],pmin[N<<];
int lastl,lastr;
void build(int k,int l,int r)
{
if(l==r)
{
maxx[k]=minn[k]=a[l];
pmax[k]=pmin[k]=pos[l];
return ;
}
int mid=l+r>>;
build(ls(k),l,mid);
build(rs(k),mid+,r);
maxx[k]=max(maxx[ls(k)],maxx[rs(k)]);
minn[k]=min(minn[ls(k)],minn[rs(k)]);
pmax[k]=max(pmax[ls(k)],pmax[rs(k)]);
pmin[k]=min(pmin[ls(k)],pmin[rs(k)]);
}
int qmax(int k,int l,int r,int L,int R)
{
if(L<=l&&R>=r)
{
return maxx[k];
}
int mid=l+r>>,res=;
if(L<=mid)res=max(res,qmax(ls(k),l,mid,L,R));
if(R>mid)res=max(res,qmax(rs(k),mid+,r,L,R));
return res;
}
int qmin(int k,int l,int r,int L,int R)
{
if(L<=l&&R>=r)
{
return minn[k];
}
int mid=l+r>>,res=0x3f3f3f3f;
if(L<=mid)res=min(res,qmin(ls(k),l,mid,L,R));
if(R>mid)res=min(res,qmin(rs(k),mid+,r,L,R));
return res;
}
int qpmax(int k,int l,int r,int L,int R)
{
if(L<=l&&R>=r)
{
return pmax[k];
}
int mid=l+r>>,res=;
if(L<=mid)res=max(res,qpmax(ls(k),l,mid,L,R));
if(R>mid)res=max(res,qpmax(rs(k),mid+,r,L,R));
return res;
}
int qpmin(int k,int l,int r,int L,int R)
{
if(L<=l&&R>=r)
{
return pmin[k];
}
int mid=l+r>>,res=0x3f3f3f3f;
if(L<=mid)res=min(res,qpmin(ls(k),l,mid,L,R));
if(R>mid)res=min(res,qpmin(rs(k),mid+,r,L,R));
return res;
}
int main()
{
n=read();
for(int i=;i<=n;i++)
a[i]=read(),pos[a[i]]=i;
build(,,n);
m=read();
while(m--)
{
int l=read(),r=read();
if(l==r)
{
printf("%d %d\n",l,r);
continue;
}
else if(l==&&r==n)
{
printf("%d %d\n",,n);
continue;
}
lastl=lastr=;
while(l!=lastl||r!=lastr)
{
lastl=l;lastr=r;
int maxval=qmax(,,n,l,r);
int minval=qmin(,,n,l,r);
l=qpmin(,,n,minval,maxval);
r=qpmax(,,n,minval,maxval);
}
printf("%d %d\n",l,r);
}
return ;
}
线段树:76pts
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define re register
const int N=; const int L=<<|;
char buffer[L],*S,*T;
#define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++) int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<='')x=x*+ch-'',ch=getchar();
return x*f;
}
int a[N],n,m,pos[N],stmax[N][][],lg[N]={-},stmin[N][][];
int lastl,lastr;
void ini()
{
for(re int i=;i<=n;i++)
stmax[i][][]=stmin[i][][]=a[i],stmax[i][][]=stmin[i][][]=pos[i],lg[i]=lg[i>>]+;
for(re int i=;i<=lg[n];i++)
for(re int j=;j+(<<i)-<=n;j++)
for(re int k=;k<=;k++)
stmax[j][i][k]=max(stmax[j][i-][k],stmax[j+(<<(i-))][i-][k]),
stmin[j][i][k]=min(stmin[j][i-][k],stmin[j+(<<(i-))][i-][k]);
}
inline int qmax(int l,int r,int k)
{
int len=lg[r-l+];
return max(stmax[l][len][k],stmax[r-(<<len)+][len][k]);
}
inline int qmin(int l,int r,int k)
{
int len=lg[r-l+];
return min(stmin[l][len][k],stmin[r-(<<len)+][len][k]);
}
void test()
{
int L=read(),R=read();
cout<<qmax(L,R,)<<' '<<qmin(L,R,)<<endl;
}
int main()
{
n=read();
for(re int i=;i<=n;i++)
a[i]=read(),pos[a[i]]=i;
ini();
//while(1)test();
m=read();
while(m--)
{
int l=read(),r=read();
if(l==r)
{
printf("%d %d\n",l,r);
continue;
}
else if(l==&&r==n)
{
printf("%d %d\n",,n);
continue;
}
lastl=lastr=;
while(l!=lastl||r!=lastr)
{
lastl=l;lastr=r;
int maxval=qmax(l,r,);
int minval=qmin(l,r,);
l=qmin(minval,maxval,);
r=qmax(minval,maxval,);
}
printf("%d %d\n",l,r);
}
return ;
}
ST表:84pts
这种算法对于随机数据已经相当优秀了,奈何数据就是要卡你这种复杂度没有保证的qjyq。满分做法也很多,分块预处理询问/线段树扫描线/线段树建图+缩点+线段树查询并集 都可以做。我写了一下理论复杂度最低但常数最大会被第一种踩爆的建图做法。
(时间不够了先放代码题解回头补咕咕咕)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
#define ls(k) k<<1
#define rs(k) k<<1|1 const int L=<<|;
char buffer[L],*S,*T;
#define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++) int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<='')x=x*+ch-'',ch=getchar();
return x*f;
}
const int N=;
int n,m,a[N],pos[N];
struct qj
{
int l,r;
qj()
{
l=0x3f3f3f3f;r=;
}
qj(int l1,int r1)
{
l=l1,r=r1;
}
};
qj operator + (const qj &x,const qj &y)
{
return qj(min(x.l,y.l),max(x.r,y.r));
}
struct segtree
{
qj t[N];
void change(int k,int l,int r,int loc,qj val)
{
if(l==r)
{
t[k]=val;
return ;
}
int mid=l+r>>;
if(loc<=mid)change(ls(k),l,mid,loc,val);
else change(rs(k),mid+,r,loc,val);
t[k]=t[ls(k)]+t[rs(k)];
}
qj query(int k,int l,int r,int L,int R)
{
if(L<=l&&R>=r)return t[k];
int mid=l+r>>;
if(L<=mid&&R>mid)
return query(ls(k),l,mid,L,R)+query(rs(k),mid+,r,L,R);
if(L<=mid)
return query(ls(k),l,mid,L,R);
if(R>mid)
return query(rs(k),mid+,r,L,R);
}
}seg[];
vector<int> g1[N],g2[N];
void build(int k,int l,int r)
{
if(l==r)
{
pos[l]=k;
return ;
}
int mid=l+r>>;
build(ls(k),l,mid);
build(rs(k),mid+,r);
g1[k].push_back(ls(k));
g1[k].push_back(rs(k));
}
void addedge(int k,int l,int r,int L,int R,int node)
{
if(L<=l&&R>=r)
{
g1[node].push_back(k);
return ;
}
int mid=l+r>>;
if(L<=mid)addedge(ls(k),l,mid,L,R,node);
if(R>mid)addedge(rs(k),mid+,r,L,R,node);
}
qj t1[N],t2[N];
int low[N],dfn[N],ind,st[N],bel[N],scc,vis[N],top;
void tarjan(int x)
{
dfn[x]=low[x]=++ind;
vis[x]=;st[++top]=x;
int sz=g1[x].size();
for(int i=;i<sz;i++)
{
int y=g1[x][i];
if(!dfn[y])
tarjan(y),low[x]=min(low[x],low[y]);
else if(vis[y])
low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x])
{
scc++;
int now;
do
{
now=st[top--];
vis[now]=;
bel[now]=scc;
}while(now!=x);
}
}
bool v[N];
void dfs(int x)
{
if(v[x])return ;
v[x]=;
int sz=g2[x].size(),y;
for(int i=;i<sz;i++)
y=g2[x][i],dfs(y),t2[x]=t2[x]+t2[y];
}
int main()
{
n=read();build(,,n);
for(int i=;i<=n;i++)
a[i]=read();
for(int i=;i<=n;i++)
seg[].change(,,n,a[i],{i,i});
for(int i=;i<=n;i++)
{
int x=min(a[i-],a[i]),y=max(a[i-],a[i]);
t1[pos[i]]=seg[].query(,,n,x,y);
addedge(,,n,t1[pos[i]].l+,t1[pos[i]].r,pos[i]);
}
for(int i=;i<N-;i++)
if(!dfn[i])tarjan(i);
for(int x=;x<N-;x++)
{
int sz=g1[x].size();//if(!sz)continue;
for(int i=;i<sz;i++)
{
int y=g1[x][i];
if(bel[x]!=bel[y])
g2[bel[x]].push_back(bel[y]);
}
}
for(int i=;i<N-;i++)
t2[bel[i]]=t2[bel[i]]+t1[i];
for(int i=;i<=scc;i++)
dfs(i);
for(int i=;i<=n;i++)
seg[].change(,,n,i,t2[bel[pos[i]]]);
m=read();
while(m--)
{
int l=read(),r=read();
if(l==r)
{
printf("%d %d\n",l,r);
continue;
}
qj ans=seg[].query(,,n,l+,r);
printf("%d %d\n",ans.l,ans.r);
}
return ;
}
又臭又长
[NOIP模拟13]题解的更多相关文章
- 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程
数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...
- 「题解」NOIP模拟测试题解乱写II(36)
毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...
- HZOJ 20190818 NOIP模拟24题解
T1 字符串: 裸的卡特兰数题,考拉学长讲过的原题,就是bzoj3907网格那题,而且这题更简单,连高精都不用 结论$C_{n+m}^{n}-C_{n+m}^{n+1}$ 考场上10min切掉 #in ...
- 「题解」NOIP模拟测试题解乱写I(29-31)
NOIP模拟29(B) T1爬山 简单题,赛时找到了$O(1)$查询的规律于是切了. 从倍增LCA那里借鉴了一点东西:先将a.b抬到同一高度,然后再一起往上爬.所用的步数$×2$就是了. 抬升到同一高 ...
- HGOI NOIP模拟4 题解
NOIP国庆模拟赛Day5 题解 T1 马里奥 题目描述 马里奥将要参加 NOIP 了,他现在在一片大陆上,这个大陆上有着许多浮空岛,并且其中一座浮空岛上有一个传送门,马里奥想要到达传送门从而前往 N ...
- NOIP模拟 13
我终于又厚颜无耻地赖着没走 ...... T1 矩阵游戏 用了30hmin找规律,然后发现貌似具有交换律,然后发现貌似有通项公式,然后发现貌似每次操作对通项的影响是相同的,然后发现貌似跟N没啥关系.. ...
- Noip模拟13 2021.7.13:再刚题,就剁手&&生日祭
T1 工业题 这波行列看反就非常尴尬.....口糊出所有正解想到的唯独行列看反全盘炸列(因为和T1斗智斗勇两个半小时...) 这题就是肯定是个O(n+m)的,那就往哪里想,a,b和前面的系数分开求,前 ...
- 8.3 NOIP 模拟12题解
话说这次考试T1和T2是真的水,然而T1CE,T2TLE,T3CE 这不就是在侮辱我的智商啊!之前本机编译都是c++,以后要用c++11. 这次的T1就是一个大型找规律,我的规律都找出来了,但是竟然用 ...
- HZOJ 20190819 NOIP模拟26题解
考试过程: 照例开题,然后觉得三道题都挺难,比昨天难多了(flag×1),T1 dp?T2 数据结构? T3 dp?事实证明我是sb然后决定先搞T2,但是,woc,这题在说什么啊,我怎么看不懂题啊,连 ...
随机推荐
- POJ 1321 棋盘问题(dfs入门)
Description 在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别.要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子 ...
- 【Flutter学习】之深入浅出 Key
一,前言 在开发 Flutter 的过程中你可能会发现,一些小部件的构造函数中都有一个可选的参数——Key.在这篇文章中我们会深入浅出的介绍什么是 Key,以及应该使用 key 的具体场景. 二,什么 ...
- linux下svn安装、配置及钩子
一.安装 直接运行命令用YUM安装: yum install subversion -y 二.创建svn版本库目录 mkdir -p /var/svn/svnrepos 三.创建版本库 生成文 ...
- electron-vue中点击按钮,实现打开程序目录里面的某个文件
设计到的知识点: explorer.exe /select 打开文件夹并把焦点放到指定文件 nodejs中的process模块--child_process.exec 我这里是根据需求,点击按钮后打开 ...
- nginx防止SQL注入规则
$request_uriThis variable is equal to the *original* request URI as received from the client includi ...
- 探索Redis设计与实现13:Redis集群机制及一个Redis架构演进实例
本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...
- 老板让我十分钟上手nx-admin
大体流程 参考资料: nx-admin项目地址 首先这里就不讲解vue和vuex之类的基础东西了 有兴趣的可以去官方文档了解.这里根据流程走向大概说说 路由配置 首先找到路由配置,路由配置放在了src ...
- 设置当内容超出div(文字长度超出div宽度)出现滚动条
overflow 一共有5个属性. 1.overflow:auto:内容会被修剪,超出设置的宽高后会出现滚动条 2.overflow:scroll;内容会被修剪,不管内容是否超出,都会出现滚动条的位置 ...
- STM32例程之USB HID双向数据传输(源码下载)【转】
程序功能 将STM32的USB枚举为HID设备. STM32使用3个端点,端点0用于枚举用,端点1和2用于数据的发送和接收. 端点长度为64,也就是单次最多可以传输64个字节数据. STM32获取上位 ...
- Java第四次作业,面向对象高级特性(继承和多态)
Java第四次作业-面向对象高级特性(继承和多态) (一)学习总结 1.学习使用思维导图对Java面向对象编程的知识点(封装.继承和多态)进行总结. 2.阅读下面程序,分析是否能编译通过?如果不能,说 ...