[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,这题在说什么啊,我怎么看不懂题啊,连 ...
随机推荐
- sql server 建表,增删改练习
use master --drop database Class create database Class on primary( name='Class', filename='D:\SQLTes ...
- mysql5.6配置-my
# mkdir -p /home/mysql/3306/{data,binlog,logs} [client] port = socket=/tmp/my3306.sock [mysql] no-au ...
- 新手指南:DVWA-1.9全级别教程之SQL Injection
*本文原创作者:lonehand,转载须注明来自FreeBuf.COM 目前,最新的DVWA已经更新到1.9版本(http://www.dvwa.co.uk/),而网上的教程大多停留在旧版本,且没有针 ...
- Ubuntu安装可视化电脑配置视图工具neofetch
安装步骤: sudo apt-get install software-properties-common python-software-propertiessudo add-apt-reposit ...
- pat甲级题目1001 A+B Format详解
pat1001 A+B Format (20 分) Calculate a+b and output the sum in standard format -- that is, the digits ...
- JavaFX教程
JavaFX是Java的下一代图形用户界面工具包.JavaFX是一组图形和媒体API,我们可以用它们来创建和部署富客户端应用程序. JavaFX允许开发人员快速构建丰富的跨平台应用程序.JavaFX通 ...
- python之模块导入方法总结
模块在python编程中的地位举足轻重,熟练运用模块可以大大减少代码量,以最少的代码实现复杂的功能. 下面介绍一下在python编程中如何导入模块: (1)import 模块名:直接导入,这里导入模块 ...
- python之命名元组的好处
collections.namedtuple() 命名元组的一个主要用途是将你的代码从下标操作中解脱出来举例使用 # 使用 from collections import namedtuple Sub ...
- JS浏览器事件循环机制
文章来自我的 github 博客,包括技术输出和学习笔记,欢迎star. 先来明白些概念性内容. 进程.线程 进程是系统分配的独立资源,是 CPU 资源分配的基本单位,进程是由一个或者多个线程组成的. ...
- stat - 打印信息节点(inode)内容
SYNOPSIS(总览) stat filename [filenames ... ] DESCRIPTION(描述) stat 打印出一个信息节点的内容,它们显示为对人可读的格式的stat(2). ...