NOIP模拟赛(10.17):语言,色球,斐波,偶数
语言
题面:
牛妹正在学习一种新的语言,在这种语言里,单词只有形容词(\(\texttt{A}\)),名词(\(\texttt{N}\))和动词(\(\texttt{V}\))三种词性。但是一个单词可以对应多种词性。
一个名词性词组(\(\texttt{NP}\))可以由一个名词(\(\texttt{N}\)),或者一个形容词修饰一个子名词性词组(\(\texttt{A} + \texttt{NP}_1\)),或者两个子名词性词组(\(\texttt{NP}_1 + \texttt{NP}_2\))组成。即:
\]
一个句子(\(\texttt{S}\))必须由一个名词性词组(\(\texttt{NP}_1\))加一个动词(\(\texttt{V}\))再加一个名词性词组(\(\texttt{NP}_2\))组成,即:
\]
牛妹用这个语言写下一个单词的序列,现在你想知道这个单词序列是否能通过适当安排序列里每个单词的词性使之成为一个句子(不同位置的相同的单词也可以安排不同的词性)。
为了简单起见,她把每个单词编码对应为一个小写拉丁字母,不同的单词对应不同的字母(这里我们假设序列里面不同的单词的总数不超过 \(26\) 个)。每个单词用 \(1(001_{(2)})\) 到 \(7(111_{(2)})\) 来表示这个单词的词性。数字的二进制第 \(1\) 位为 \(1\) 表示这个单词可以作为形容词(\(\texttt{A}\)),否则表示无法作为形容词;第 \(2\) 位为 \(1\) 表示这个单词可以作为名词(\(\texttt{N}\)),否则表示无法作为名词;第 \(3\) 位为 \(1\) 表示这个单词可以作为动词(\(\texttt{V}\)),否则表示无法作为动词。
具体的对应关系如下表所示:
编码 | 词性 |
---|---|
\(1\) | \(\texttt{A}\) |
\(2\) | \(\texttt{N}\) |
\(3\) | \(\texttt{A} \text{ or } \texttt{N}\) |
\(4\) | \(\texttt{V}\) |
\(5\) | \(\texttt{A} \text{ or } \texttt{V}\) |
\(6\) | \(\texttt{N} \text{ or } \texttt{V}\) |
\(7\) | \(\texttt{A} \text{ or } \texttt{N} \text{ or } \texttt{V}\) |
题解:
$O(Tn)$做法 ($100$pts):
注意到一个句子中动词有且仅有一个,所以对于类型4单词数大于1的情况,直接输出NO即可
根据题意,只要是一个不包含动词且以名词结尾的字符串则一定可以视为一个名词词组(即$NP$)
发现动词前必须为名词类型,结尾必须为名词类型
所以枚举动词位置,判断动词前及句末是否有名词即可,若存在类型4且数量为一,则动词一定为类型4单词
Code:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int w[26],a[N],n,cnt,pos;
string s1;
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
// freopen("language.in","r",stdin);
// freopen("language.out","w",stdout);
int t;
cin>>t;
while(t--){
cnt=0,pos=0;
for(int i=0;i<26;i++)cin>>w[i];
cin>>s1;
n=s1.length();
for(int i=1;i<=n;i++){
a[i]=w[s1[i-1]-'a'];
if(a[i]==4)cnt++,pos=i;//记录类型4单词数量
}
if(a[n]==1||a[n]==4||a[n]==5||cnt>1){
cout<<"No\n";
continue;
}
if(cnt==1){
if(a[pos-1]==0||a[pos-1]==1||a[pos-1]==5){
cout<<"No\n";
continue;
}else {
cout<<"Yes\n";
continue;
}
}
bool suc=1;
for(int i=2;i<n;i++){
if((a[i]==5||a[i]==6||a[i]==7)&&(a[i-1]==2||a[i-1]==3||a[i-1]==6||a[i-1]==7)){
cout<<"Yes\n";//枚举动词位置
suc=0;
break;
}
}
if(suc)cout<<"No\n";
}
return 0;
}
色球
题面:
牛牛有 \(n\) 种颜色的彩色小球(编号 \(1\) 到 \(n\)),每种颜色的小球他都有无限多个。他还有 \(n\) 个球桶(编号 \(1\) 到 \(n\)),球桶的内径与小球直径相当且高度是无限大的,因此能容纳无限多的小球。他想用这些小球和球桶玩游戏。
一开始这些球桶都是空的,紧接着他会依次做 \(m\) 个操作,每个操作都是以下 \(3\) 种操作中的一个:
push x y z
,表示把 \(x\) 个颜色为 \(y\) 的彩色小球放到第 \(z\) 个桶的最上面;pop x z
,表示把最上面的 \(x\) 个小球从第 \(z\) 个桶内拿出来;put u v
,表示把第 \(u\) 个桶的所有小球依次从顶部拿出放入第 \(v\) 个桶内。
现在他已经确定好了这 \(m\) 个操作都是什么,但在他开始玩之前,他想知道每次他进行第二类操作取出的最后一个小球是什么颜色。
题解:
$O(n \log n)$做法($100$pts):
fhq平衡树维护序列,代码难度较大(考场上写两个半小时,还是炸到70分),序列翻转,删除,合并都是经典操作。文艺平衡树
Code:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4002000;
int n,m,root[N],tot;
namespace treap{
struct fhq_treap{
int ls,rs,col,val,rev;
ll sz,num;
}tr[N];
void init(){
tr[0].ls=0;
tr[0].rs=0;
tr[0].val=0;
tr[0].num=0;
tr[0].sz=0;
tr[0].col=0;
tr[0].rev=0;
}
int newnode(int col,ll num){
++tot;
tr[tot].val=rand()*rand();
tr[tot].col=col,tr[tot].sz=tr[tot].num=num;
tr[tot].ls=tr[tot].rs=0;
tr[tot].rev=0;
return tot;
}
void pushup(int rt){
tr[rt].sz=tr[rt].num;
if(tr[rt].ls){
tr[rt].sz+=tr[tr[rt].ls].sz;
}
if(tr[rt].rs){
tr[rt].sz+=tr[tr[rt].rs].sz;
}
}
void pushdown(int rt){
if(tr[rt].rev){
if(tr[rt].ls){
tr[tr[rt].ls].rev^=1,swap(tr[tr[rt].ls].ls,tr[tr[rt].ls].rs);
}
if(tr[rt].rs){
tr[tr[rt].rs].rev^=1,swap(tr[tr[rt].rs].ls,tr[tr[rt].rs].rs);
}
tr[rt].rev=0;
}
}
int merge(int x,int y){
if((!x)||(!y)){
return x|y;
}
pushdown(x),pushdown(y);
int rt;
if(tr[x].val<tr[y].val){
rt=x;
tr[rt].rs=merge(tr[x].rs,y);
}
else{
rt=y;
tr[rt].ls=merge(x,tr[y].ls);
}
pushup(rt);
return rt;
}
void split(int rt,ll k,int &x,int &y,int &z){
if(!rt){
x=y=z=0;
return;
}
pushdown(rt);
if(tr[tr[rt].rs].sz>=k){
x=rt;
split(tr[rt].rs,k,tr[rt].rs,y,z);
}
else if(tr[tr[rt].rs].sz+tr[rt].num<k){
z=rt;
split(tr[rt].ls,k-tr[tr[rt].rs].sz-tr[rt].num,x,y,tr[rt].ls);
}
else{
x=tr[rt].ls,z=tr[rt].rs;
y=rt;
tr[rt].ls=tr[rt].rs=0;
}
pushup(rt);
}
void pop_nd(int x,int k){
int a,b,c;
split(root[x],k,a,b,c);
root[x]=merge(a,newnode(tr[b].col,tr[c].sz+tr[b].num-k));
cout<<tr[b].col<<endl;
}
}
using namespace treap;
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
freopen("ball.in","r",stdin);
freopen("ball.out","w",stdout);
string s;
cin>>n>>m;
for(int cas=1;cas<=m;++cas){
cin>>s;
int x,y,z;
if(s=="push"){
cin>>x>>y>>z;
root[z]=merge(root[z],newnode(y,x));
}
else if(s=="put"){
cin>>x>>y;
tr[root[x]].rev^=1;
swap(tr[root[x]].ls,tr[root[x]].rs);
root[y]=merge(root[y],root[x]);
root[x]=0;
}else{
cin>>x>>y;
pop_nd(y,x);
}
init();
}
return 0;
}
$O(n)$做法($100$pts):
每个位置用双向链表顺序记录放的球的个数和颜色。
对于询问$1$,往位置$z$的链表上加一个结点$(,)$。
对于询问$2$,从位置$z$的链表头取,如果当前需要取$$个而当前结点拥有的球 $′<$个,则整个结点删掉,$$更新为$−′$。如果$′≥$,那么输出当前的颜色 $′$,并且把$′$更新为$′−$。
对于询问$3$,把位置$$的链表头直接拼接到位置$$的链表头上,位置$$的链表尾作为位置$$新的链表头。
代码难度相对较小。
Code:
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 301001;
struct node {
int c,num,ch[2];
} buf[maxn];
int n,m,h[maxn],t[maxn],tot;//h:链表头 t:链表尾
int main() {
freopen("ball.in","r",stdin);
freopen("ball.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=0; i<m; i++) {
char op[6];
int x,y,z;
scanf("%s%d%d",op,&x,&y);
if (op[2]=='s') {
scanf("%d",&z);
buf[++tot]=(node){y,x,h[z],0};
if (h[z])
buf[h[z]].ch[0]?(buf[h[z]].ch[1]=tot):(buf[h[z]].ch[0]=tot);//将链表空的一头连接新点
else t[z]=tot;//若链表为空,将该点作为链表尾
h[z]=tot;//更新链表头
}
if (op[2]=='p') {
while (buf[h[y]].num<x) {
x-=buf[h[y]].num;
int lch=buf[h[y]].ch[0]|buf[h[y]].ch[1];//获取链表头的下一个节点
if (lch)buf[lch].ch[0]==h[y]?(buf[lch].ch[0]=0):(buf[lch].ch[1]=0);//删除链表头
h[y]=lch;//更新链表头
}
buf[h[y]].num-=x//减去剩余的
printf("%d\n",buf[h[y]].c);
}
if(op[2]=='t'){
if (!h[x]) continue;//若链表x为空,跳过该操作
if (h[y]) {//完成链表头的连接
buf[h[y]].ch[0]?(buf[h[y]].ch[1]=h[x]):(buf[h[y]].ch[0]=h[x]);//将y链表头空的一头连向x的链表头
buf[h[x]].ch[0]?(buf[h[x]].ch[1]=h[y]):(buf[h[x]].ch[0]=h[y]);//将x链表头空的一头连向y的链表头
} else {
t[y]=h[x]; //若链表y为空,则直接将用x链表头作为y的尾部
}
h[y]=t[x];//更新y链表头
h[x]=t[x]=0;//清空x链表
}
}
return 0;
}
偶数
题面:
牛牛喜欢偶数,他定义一种新的『偶数』为:数字的位数(在十进制下,去掉前导零)为偶数,且数字前一半和后一半完全一致。比如 \(121121\)、\(12341234\) 是『偶数』,而 \(111\)、\(121212\) 不是『偶数』。
对于一个『偶数』,牛牛可以在这个『偶数』后继续添加数字,使得它成为新的『偶数』。比如,\(121121\) 可以在后面添加数字,使之变成 \(1211212112\) 成为新的『偶数』。牛牛总是想添加最少的数字获得新的『偶数』。可以证明添加的方式是唯一的。
对于任何一个『偶数』,牛牛都可以通过上述的方式产生新的『偶数』,这个新的『偶数』继续产生下一个新的『偶数』,直到这个『偶数』的位数超过任意给定的正整数 \(n\) 为止。之后,牛牛会多次询问你,这个最终的『偶数』的第 \(l\) 位到第 \(r\) 位(\(1 \le l \le r \le n\))组成的整数对 \(998244353\) 取模的结果是多少。
题解:
$O(n+q)$做法($40$pts):
假设是,那么新的“偶数”必然是的形式,其中是的一个前缀,且是 的一个周期。可以证明应该取最小的周期。因此使用KMP求的周期,每
次得到后,新的作为继续求周期,直到的长度超过为止。
询问时预处理$[]$为区间$[1,]$的答案,则$[,]$的答案为$[]−[−1]×10^{r−l+1}$。
$O(\vert S \vert + q \log n)$做法($100$pts):
设$v_0=w$,$v_1=v$,$v_i=v_{i-1}v_{i-2}$,发现最终的字符串一定是$v_{\infty}$的一个前缀,由此我们可以考虑倍增,但在这之前,我们需要证明一个结论
\(w\)是\(v\)的最短周期,且\(len(w)\)不是\(len(v)\)的因子,则\(vw\)的最短的周期是\(v\)
证明:假设$$的最短的周期是$$,$()<()$。
如果$()≡() \ ()$,$((),())$也是的周期,矛盾。
如果$ ()≢() \ ()$,$((),(()−())%())$是的周期,从而是的周期,矛盾。
所以我们只需要预处理$\log n$个$v_i$的长度和值,在处理$[1,l]$和$[1,r]$的值时按长度从大到小的增加即可
Code:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
const int N=1e5+10;
const int M=100;
#define int long long
char s[N];
int leng,lim,n,q,l,r;
int nxt[N],len[M],f[M],fs[N],base[M];
//快速幂
int qpow(int a,int b){
int res=1;
while(b>0){
if(b&1)res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res%mod;
}
//KMP
void get_nxt(){
nxt[1]=0;
for(int i=2,j=0;i<=leng;i++){
while(j&&s[j+1]!=s[i])j=nxt[j];
if(s[j+1]==s[i])j++;
nxt[i]=j;
}
}
//倍增
int get_ans(int r){
int sum=0,ans=0;
for(int i=lim;i>=0;i--){
if(sum+len[i]<=r){
sum+=len[i];
ans=(ans*base[i]%mod+f[i])%mod;
}
}
return (ans*qpow(10,r-sum)%mod+fs[r-sum])%mod;//处理剩余部分
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
freopen("code.in","r",stdin);
int t;
cin>>t;
while(t--){
cin>>s+1>>n>>q;
leng=strlen(s+1)/2;
for(int i=1;i<=leng;i++)fs[i]=(fs[i-1]*10LL+s[i]-'0')%mod;//预处理原字符串对应数字
get_nxt();
len[0]=leng-nxt[leng],len[1]=leng;
f[0]=fs[len[0]],f[1]=fs[len[1]];
lim=1;
//倍增
for(int i=2;i<=100;i++){
len[i]=len[i-1]+len[i-2];
f[i]=(f[i-1]*qpow(10,len[i-2])%mod+f[i-2])%mod;
if(len[i]>=n){
lim=i;
break;
}
}
for(int i=0;i<=lim;i++)base[i]=qpow(10,len[i]);//预处理10的幂
for(int i=1;i<=q;i++){
cin>>l>>r;
//截取l-r的数字
cout<<(get_ans(r)-get_ans(l-1)*qpow(10,r-l+1)%mod+mod)%mod<<"\n";
}
}
return 0;
}
结束咯(T3先鸽着)
NOIP模拟赛(10.17):语言,色球,斐波,偶数的更多相关文章
- noip模拟赛Bywzj52501 17.10.18
T1 rob 环形消灭虫子 先想出了一个n^2暴力 然后我们想到 如果从两个连续的点求解 则会出现仅有的两种结果 (因为这两种情况的交是全集) 当时因为Naive求了50次 #include<i ...
- 【noip模拟赛10】奇怪的贸易 高精度
描述 刚结束了CS战斗的小D又进入了EVE的游戏世界,在游戏中小D是一名商人,每天要做的事情就是在这里买东西,再运到那里去卖.这次小D来到了陌生的X星,X星上有n种货物,小D决定每种都买走一些,他用a ...
- noip 模拟赛 After 17(递推+特殊的技巧)
来源:Violet_II T1 好神的一题,我竟然没做出来QAQ 首先我们发现,答案是sigma(x[i]*x[j], i>j)+sigma(y[i]*y[j], i>j).显然只需要讨论 ...
- NOIP模拟赛10 题解
t3: 题意 给你一棵树,然后每次两种操作:1.给一个节点染色 : 2. 查询一个节点与任意已染色节点 lca 的权值的最大值 分析 考虑一个节点被染色后的影响:令它的所有祖先节点(包括自身)的所有除 ...
- NOIP模拟赛10
T1 [HAOI2010]软件安装 https://daniu.luogu.org/problem/show?pid=2515 树上背包,如果有i必须有j,j作为i的父节点 O(nm²) #inclu ...
- 10.17 NOIP模拟赛
目录 2018.10.17 NOIP模拟赛 A 咒语curse B 神光light(二分 DP) C 迷宫maze(次短路) 考试代码 B 2018.10.17 NOIP模拟赛 时间:1h15min( ...
- 10.16 NOIP模拟赛
目录 2018.10.16 NOIP模拟赛 A 购物shop B 期望exp(DP 期望 按位计算) C 魔法迷宫maze(状压 暴力) 考试代码 C 2018.10.16 NOIP模拟赛 时间:2h ...
- NOIP模拟赛 by hzwer
2015年10月04日NOIP模拟赛 by hzwer (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...
- NOI.AC NOIP模拟赛 第五场 游记
NOI.AC NOIP模拟赛 第五场 游记 count 题目大意: 长度为\(n+1(n\le10^5)\)的序列\(A\),其中的每个数都是不大于\(n\)的正整数,且\(n\)以内每个正整数至少出 ...
- NOIP模拟赛20161022
NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...
随机推荐
- PADS无模命令总结表
无模命令总结表 1.C 补充格式,在内层负片设计时用来显示 Plane 层的焊盘及 Thermal.使用方法是,从键盘上输入 C 显示,再次输入 C 可去除显示. 2.D 打开/关闭当前层显示,使用方 ...
- DXF文件导入PADS板框问题
在使用PADS时,经常会从CAD文件中导出板框形状到PADS中. 也经常碰到一个问题:就是单位不匹配,CAD中明明设置成毫米了,可导入到PADS时却是mil. 发现单位不匹配的情况跟AUTOCAD里面 ...
- Springboot集成easypoi实现excel多sheet导出
1.环境配置 <!--easypoi依赖,excel导入导出--> <dependency> <groupId>cn.afterturn</groupId&g ...
- MySQL 查询时间
mysql 查询当天.最近一天.最近一周,本月,上一个月的数据 今天 select * from 表名 where to_days(时间字段名) = to_days(now()); 昨天 SELECT ...
- 一个nginx + vue下二级路径版本化方案
PS: 尽量不要做版本化!尽量不要做版本化!尽量不要做版本化! 过程说明: 1.arg_appver表示读取url上appver参数 2.对appver参数做变量映射得到alias_party1_te ...
- 为什么 退出登录 或 修改密码 无法使 token 失效
前文说过 token 由 3 个部分组成:分别是 token metadata,payload,signature, 其中 signature 部分是对 payload 的加密,而 payload 当 ...
- go实现协程池管理
使用channel实现协程池 通过 Channel 实现 Goroutine Pool,缺点是会造成协程的频繁开辟和注销,但好在简单灵活通用. package main import ( " ...
- Golang 入门 : 字符串及底层字符类型
字符串 基本使用 在 Go 语言中,字符串是一种基本类型,默认是通过 UTF-8 编码的字符序列,当字符为 ASCII 码时则占用 1 个字节,其它字符根据需要占用 2-4 个字节,比如中文编码通常需 ...
- 【WPF开发】 direct3d11 调试报错
环境:VS2022 WPF Win11 过程:准备调试d3d11着色器转换nv12->rgb的过程 报错信息:DXGI_ERROR_SDK_COMPONENT_MISSING 应用程序请求的操作 ...
- 原生JS实现虚拟列表(不使用Vue,React等前端框架)
好家伙, 1. 什么是虚拟列表 虚拟列表(Virtual List)是一种优化长列表渲染性能的技术.当我们需要展示成千上万条数据时,如果一次性将所有数据渲染到DOM中,会导致页面卡顿甚至崩溃.虚拟 ...