noip模拟12 solutions

这次考试靠的还是比较好的,但是还是有不好的地方,

为啥嘞??因为我觉得我排列组合好像白学了诶,文化课都忘记了

    正难则反!!!!!!!!

害没关系啦,一共拿到了\(120pts\),其实距离我的理想分数还差那么\(100pts\)

具体是这样的,第一题AC,第二题10,第三题10

下次要把知识都回忆一下,比如这次用到的欧拉定理,差一点就忘记了

noip模拟13!!!200分!!

·

·

·

T1 简单的区间

哈哈哈这个题是我这几次考试中最成功的一道了,所以我一定要好好讲一讲我的STL算法

(因为正解好像是主席树 逃)(我现在对这树那树的非常恶心)

首先我第一眼看到这个题面的时候,我直接就想到了昨天\(noip11\)那场的\(T3\)

同样是求有关于最大值的结果,还是在区间上,那必须是单调栈走起啊,好像有人还不会诶

priority_stack

这里是利用数组来实现的单调栈,相比普通的STL栈来说要好理解
sta为栈数组,tot为栈顶 每一次向栈中加入值的时候,都把栈中小于等于它的数弹出,并将这些弹出的元素右边界赋值为i-1
注意判断栈中是否还有元素!!1
弹完之后将现在插入的值的左边界赋值为sta[tot]+1;就是栈顶元素的右边一位
最后,将栈中元素全部弹出,右边界复制为n
for(re i=1;i<=n;i++){
while(tot&&a[i]>=a[sta[tot]])r[sta[tot]]=i-1,tot--;
//弹出+右边界
l[i]=sta[tot]+1;
//左边界
sta[++tot]=i;
//加入栈中
}
while(tot)r[sta[tot]]=n,tot--;
//给右边界赋值


然后我们找到左右边界之后,再回来看这个题,

求的是区间和减去最大值\(\mod k==0\)所以,既然涉及到区间求和,那前缀和是必不可少的

设前缀和数组为\(fro[]\),左边界为\(i\),右边界为\(j\),此时区间最大值的坐标为\(x\)

那么我们有一个结论\(fro[j]-fro[i-1]-a[x]=0\)(此处省略一堆+k、%k)

既然这样我们为了好处理这个式子,我们把所有的\(fro[i]\)、\(a[i]\)对\(k\)取模

接下来我们就可以利用一个\(vector\)数组来存储每一个状态

vec[tmp],是一个\(vector\)类型表示余数为tmp的坐标都有哪些,

在插入值的时候,我们只需要从1~n遍历一遍,然后vec[tmp].push_back(i)就好了

(因为是顺序插入,所以每一个\(vector\)中都是排好序的坐标)

然后我们在左右区间内选取较小的那一段来进行枚举(假设选取左边较小)

那么右边界的前缀和就可以由\(fro[i-1]+a[x]\)来求出,那么我们就可以直接在\(vector\)中查找在x~r这个区间内的数有多少

这个操作可以通过STL内置函数lower_bound和upper_bound来实现

如果是右区间较短,也同理,有些细节在代码里展示

AC_code



#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=3e5+5;
const int M=1e6+5;
int n,k;
int a[N],fro[N];
int ys[M],ji[M],cnt;
int l[N],r[N],sta[N],tot;
vector<int> vec[M];
ll ans;
void sol(int x,int l,int r){
if(x-l<r-x){
for(re i=l;i<=x;i++){
int tmp=(fro[i-1]+a[x])%k;//注意此处fro[i-1];
int lh=lower_bound(vec[tmp].begin(),vec[tmp].end(),x)-vec[tmp].begin();
int rh=upper_bound(vec[tmp].begin(),vec[tmp].end(),r)-vec[tmp].begin();
ans+=rh-lh;
}
}
else{
for(re i=x;i<=r;i++){
int tmp=(fro[i]+k-a[x]%k)%k;//a[x]%k别忘记
int lh=lower_bound(vec[tmp].begin(),vec[tmp].end(),l-1)-vec[tmp].begin();//此处l-1
int rh=upper_bound(vec[tmp].begin(),vec[tmp].end(),x-1)-vec[tmp].begin();//x-1
ans+=rh-lh;
}
}
}
signed main(){
scanf("%d%d",&n,&k);
for(re i=1;i<=n;i++){
scanf("%d",&a[i]);
fro[i]=(fro[i-1]+a[i])%k;
ys[fro[i]]++;
if(ys[fro[i]]==1)ji[++cnt]=fro[i];//记录出现过的余数
}
for(re i=1;i<=cnt;i++){
vec[ji[i]].reserve(ys[ji[i]]+5);//限制空间
}
vec[0].push_back(0);
for(re i=1;i<=n;i++)
vec[fro[i]].push_back(i);
for(re i=1;i<=n;i++){
while(tot&&a[i]>=a[sta[tot]])r[sta[tot]]=i-1,tot--;
l[i]=sta[tot]+1;
sta[++tot]=i;
}
while(tot)r[sta[tot]]=n,tot--;
for(re i=1;i<=n;i++)sol(i,l[i],r[i]);
printf("%lld",ans-n);//最后方案数减去n,因为左边界不能等于右边界
}


你是不是看到我的代码里好像有一些并没有什么用的vector操作

那些操作可能在这个题中没啥用,但是这个很重要。看看这篇博客

T2 简单的玄学

这个题就是排列组合嘛,数学课上我就一直瞎嚷嚷:正难则反!!正难则反!!!

可是到了真正用到这个做法的时候,我倒是看不出来了,真是的

就这个题统计至少两个数相同的概率,我在考场上苦思冥想,想出来了正着做的办法,然后10pts

考完一看题解,正难则反,直接1减去两两都不相同的概率不就好了???

看的我人都傻了,咋考场上就想不出来啊,要是想出来了,起码也得有50pts啊

两两不相同的概率是

\(\dfrac{A_{2^n}^{m} }{2^{nm}}=\dfrac{\frac{2^n!}{(2^n-m)!}}{2^{nm}}=\dfrac{\prod_{i=2^n-m+1}^{2^n}}{2^{nm}}=\dfrac{\prod_{i=2^n-m+1}^{2^n-1}}{2^{n(m-1)}}\)

这样,目前在这个式子上来看,是没有啥可以约掉的啦

题目要求我们对这分子分母进行约分,仔细观察发现,这个分母的因子只有2

所以我们只需要找到分母中有多少个\(2\)就\(OK\)啦

现在有一个结论:\(2^n-a\)和\(a\)中,因子2的个数是一致的,

    因为它们两个加起来是2的幂,所以我们可以知道,这两个数同时除以相同个数的2后,
一定相加是偶数,所以只能是都是奇数或者都是偶数,都是奇数那就符合这个结论
都是偶数,那就继续除,除到是奇数为止

所以我们要寻找\(2^n-m+1\)~~~~~\(2^n-1\)这些数相乘的结果中的2的个数,

等价于找\(1~m-1\)中的2的个数,这里确实有一个\(O(logm)\)的算法,并且极其好想

O(logm) get sum of 2

这里主要是利用2的性质
m个数中,有m/2个数可以整除2,那么就有这么多个2
同理,有m/4个数可以整除4,那么就再有这么多2
........
然后就这样一直除下去,得到fz, for(ll i=2ll;i<m;i*=2ll)
fz+=(m-1)/i,fz%=(mod-1);


那么此时我们发现如果\(m>mod\)的话,那就一定有一个数是mod的倍数,那分子就变成0咯

但是此时的答案并不是1,因为%mod之后为0,并不代表原来为0

所以这样的话我们就计算分母就好啦,别忘记除掉约去的2

那要是m<mod的话,暴力计算分子,输出答案

答案是1减去你算出来的值啊啊啊啊啊啊啊啊啊啊

AC_code

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int mod=1e6+3;
ll n,m;
ll fz;
ll a,b;
ll ksm(ll x,ll y){
ll ret=1;
while(y){
if(y&1)ret=ret*x%mod;
x=x*x%mod;
y>>=1;
}
return ret;
}
signed main(){
scanf("%lld%lld",&n,&m);
for(ll i=2ll;i<m;i*=2ll)
fz+=(m-1)/i,fz%=(mod-1);
if(m>mod){
ll tmp=(n%(mod-1))*((m-1)%(mod-1))%(mod-1);
tmp=(tmp-fz+mod-1)%(mod-1);
ll bas=ksm(2ll,tmp);
printf("%lld %lld",bas,bas);
return 0;
}
a=1;
for(ll i=1;i<m;i++)a=a*(ksm(2ll,n%(mod-1))+mod-i)%mod;
a=a*ksm(ksm(2ll,fz),mod-2)%mod;
b=ksm(2ll,((n%(mod-1)*(m-1)%(mod-1))%(mod-1)+mod-1-fz)%(mod-1));
printf("%lld %lld",(b+mod-a)%mod,b);
}


T3 简单的填数

这个题考场上是真没有思路好吧,真的惨暴了

但是我在考场上确实想到了要正着走一遍,倒着走一遍,只是这个过程有点小小的复杂

然后我在考场上直接放弃了,对着我那第一题的对拍程序高兴去了

这个题主要是维护一个up和dw二元组(x,len),存储这个位置目前最大的值及其个数,最小值及其个数

所以我们就有了一个转移,

    当len==2时,up更新
当len==5时,dw更新

但是注意,在原序列上如果a[i]上有值的话:

如果当前值和a[i]相同的话,那就不需要做任何更改

如果不相等的话,那就直接赋值成a[i],

    up.len=2(因为我要让up越大越好,所以把他赋值成要更改的边界)
dw.len=1(要最小嘛)

然后就剩下倒序走一遍然后得到答案序列啦,这是最难的啦

我是记录了一个now表示从上一个标记的a[i]开始5个一组的数,目前是多少,num表示现在的now有几个

然后我们的\(ans[i]=\min({now},{up[i].x})\)

如果遇到下一个标记好的a[i],就\(now=a[i],num=0\)就行了

最后倒序输出一下这个序列就好啦

记得判断的时候有两种情况,一个是up<a[i],dw>a[i];

还有一个就是,最后一个长度不够2,输出-1;

AC_code

#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=2e5+5;
int n,a[N];
struct node{
int x,len;
}up[N],dw[N];
int ans[N];
signed main(){
scanf("%d",&n);
for(re i=1;i<=n;i++)scanf("%d",&a[i]);
up[1].x=1;up[1].len=1;
dw[1].x=1;up[1].len=1;
for(re i=2;i<=n;i++){
up[i].x=up[i-1].x;up[i].len=up[i-1].len+1;
if(up[i].len>2)up[i].x++,up[i].len=1;
dw[i].x=dw[i-1].x;dw[i].len=dw[i-1].len+1;
if(dw[i].len>5)dw[i].x++,dw[i].len=1;
if(a[i]){
if(up[i].x<a[i]||dw[i].x>a[i]){
printf("-1");return 0;
}
if(up[i].x>a[i])up[i].x=a[i],up[i].len=2;
if(dw[i].x<a[i])dw[i].x=a[i],dw[i].len=1;
}
}
if(up[n].len==1)up[n].x--,up[n].len=up[n-1].len+1;
if(up[n].x<dw[n].x){
printf("-1");return 0;
}
printf("%d\n",ans[n]=up[n].x);
int now=ans[n],num=1;
for(re i=n-1;i>=1;i--){
if(a[i]){
if(now>a[i])now=a[i],num=0;
}
if(num==5)now--,num=0;
num++;
ans[i]=min(now,up[i].x);
}
for(re i=1;i<=n;i++)printf("%d ",ans[i]);
}


完事啦

noip模拟12[简单的区间·简单的玄学·简单的填数]的更多相关文章

  1. Noip模拟12 2021.7.12

    T1 interval 亏得昨天晚上改掉了T3并且理解了单调栈,今天一扫这题目就知道要用啥了. 先预处理出以a[i]为最大值的最大左右区间.然后再将a[i]取%!!!是的,要不然会影响单调栈的使用.. ...

  2. NOIP 模拟 $12\; \text{简单的区间}$

    题解 签到题 求区间和为 \(k\) 的倍数的区间,我们可以转化为求左右两个端点,其前缀和相等 对于区间最大值,我们可以把其转化为一个值,它能向左,向右扩展的最远边界,一个单调栈即可 我们设一个值 \ ...

  3. NOIP 模拟 $12\; \text{简单的填数}$

    题解 一个纯的贪心,被我搞成 \(dp\) 了,最后把错解删掉了,骗了 \(10pts\) 考虑如何贪心,设置一种二元组 \((x,l)\),\(x\) 表示当前值,\(l\) 表示当前最长连续长度. ...

  4. NOIP 模拟 $12\; \text{简单的玄学}$

    题解 有些难度 对于 \(30pts\) 直接暴力 对于 \(70pts\) 发现规律 \(2^n-a\) 与 \(a\;\;(a\in [1,2^n))\) 分解质因数后,\(2\) 的次数相同 \ ...

  5. [考试总结]noip模拟12

    菜 今天总体来说 菜爆了,打了 \(3\) 个暴力,没有一个是正解,并且每一个分数都低得要命... 主要还是太菜了... 第一题开题发现和昨天 \(T3\) 一样,然而因为还没学可持久化数据结构就咕掉 ...

  6. NOIP模拟12

    也算是最近几次比较水的一次吧. 考试时看T1像个打表找规律的题,扔了,去看T2,带修莫队??不会,完戏.看了T3,我决定还是去看T1. 看着T1,我突然发现T2是个大水题:主席树就行,不带修,修改时只 ...

  7. NOIP模拟 12

    今天过的还真是心态炸裂.. 还是莫提了吧,今日之果一定对应着今日之因. 考试前非常心虚,莫名其妙地产生了一种紧张感(????)然后果然就在T1卡题了... T1想到了减去前一项的菲波数,但是没想到交替 ...

  8. 8.3 NOIP 模拟12题解

    话说这次考试T1和T2是真的水,然而T1CE,T2TLE,T3CE 这不就是在侮辱我的智商啊!之前本机编译都是c++,以后要用c++11. 这次的T1就是一个大型找规律,我的规律都找出来了,但是竟然用 ...

  9. noip模拟33

    \(\color{white}{\mathbb{失足而坠千里,翻覆而没百足,名之以:深渊}}\) 这场考试的时间分配非常不科学 开题试图想 \(t1\) 正解,一个半小时后还是只有暴力,特别惊慌失措 ...

随机推荐

  1. php弱类型比较

    前言:今天XCTF题目中出现了弱类型比较,特别过来记录一下, 0x01: == 是弱类型比较,两个不同类型比较时,会自动转换成相同类型后再比较值 ===是强比较,需要比较值和类型 0x02: 看下图案 ...

  2. leetcode147对链表进行插入排序

    题目: 对链表进行插入排序. 插入排序算法: 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当 ...

  3. 虚拟机centos7环境搭建,系统分区,静态IP配置

    文章目录 1.虚拟机安装centos7 2.系统分区 3.配置静态IP centos7下载地址 http://mirrors.aliyun.com/centos/7/isos/x86_64/ Cent ...

  4. ESP32-http client笔记

    基于ESP-IDF4.1 #include <string.h> #include <stdlib.h> #include "freertos/FreeRTOS.h& ...

  5. Python小白的数学建模课-B6. 新冠疫情 SEIR 改进模型

    传染病的数学模型是数学建模中的典型问题,常见的传染病模型有 SI.SIR.SIRS.SEIR 模型. SEIR 模型考虑存在易感者.暴露者.患病者和康复者四类人群,适用于具有潜伏期.治愈后获得终身免疫 ...

  6. Luogu P4553 80人环游世界

    link 题目大意 自东向西有 \(n\) 个国家.有 \(m\) 个人,他们可以选择 \(n\) 个国家中任意一个开始,任意一个结束,但路线必须自东向西,且第 \(i\) 个国家必须恰好经过 \(v ...

  7. python 图中找目标并截图

    import numpy as npdef sjjt(xha,sjh,beitu,jl,xx,yy): #检查目标,并将目标指定范围内截图 pull_screenshot(xha,sjh,xx) #p ...

  8. python -- namedtuple元组

  9. 微信小程序云开发-数据库-获取用户添加的数据到数据库

    一.列表页面新增[添加商品]按钮 在列表页增加[添加商品]按钮,按钮绑定事件toAdd(),用户点击该按钮跳转到添加商品页面. 在js文件中写toAdd()函数,作用是点击[添加商品]按钮,跳转到[添 ...

  10. 计算机基础-Socket

    计算机基础-Socket 当时明月在,曾照彩云归. 简介:计算机基础-Socket 一.I/O 模型 一个输入操作通常包括两个阶段: 等待数据准备好 从内核向进程复制数据 对于一个套接字上的输入操作, ...