[补档]noip2019集训测试赛(八)
Problem B: 2048
Special Judge
Time Limit: 1000 ms Memory Limit: 256 MB
Description
2048曾经是一款风靡全球的小游戏。
今天,我们换一种方式来玩这个小游戏。
现在,你有一个双端队列,你只能把元素从左端或从右端放入双端队列中。一旦放入就不得取出。放入后,若队列中有连续两个相同的元素,它们将自动合并变成一个新的元素——原来那两个元素的和。若新的元素与它相邻的元素相同,则继续合并……
如:双端队列中有2, 4, 16三个元素。若将2从左端插入双端队列中,该队列将变成8, 16。若将2从右端插入双端队列中,该队列将变成2, 4, 16, 2。
一开始,双端队列为空。我们将给你一些数,你需要依次插入到双端队列中。问是否存在一种操作方案,使得双端队列最后只剩下一个数。
Input
第一行为一个整数 T,表示数据组数。
对于每组测试数据:
第一行一个整数 n,表示我们给你的数的个数。
接下来一行 n个数,表示我们给你的数 ai 。这些数都是2的非负整数次方,即对于每个 i 都存在一个整数 k 满足 k≥0 且 ai=2^k 。
Output
对于每组数据,若不存在一种操作方案使得双端队列最后只剩一个数,则输出no。否则,输出一个长度为n的字符串,其中若第i个数从左边插入到双端队列,则第i个字符为 l ;若第i个数从右边插入到双端队列,则第i个字符为 r 。
Sample Input
3
9
2 8 4 1 1 4 4 4 4
5
2 16 4 8 2
3
2 2 2Sample Outputrrrlllrrr
no
no
HINT
样例1解释
1、从右边插入2,双端队列变为2
2、从右边插入8,双端队列变为2 8
3、从右边插入4,双端队列变为2 8 4
4、从左边插入1,双端队列变为1 2 8 4
5、从左边插入1,双端队列变为4 8 4
6、从左边插入4,双端队列变为16 4
7、从右边插入4,双端队列变为16 8
8、从右边插入4,双端队列变为16 8 4
9、从右边插入4,双端队列变为32
数据范围与约定
对于20%的数据, n≤19,T≤100
对于所有数据, 1≤n≤1000,a1~an的和不超过2^13,T≤10000,其中 n>20 的数据不超过150组。
Solution
考虑状压+搜索
用一个L表示一下当前状态的左半部分,那么右半部分可以用预处理的前缀和减去L表示出来
如果当前要加入的数比L的lowbit还要小,那么就加入左边
右边部分同理
然后用一个vis表示一下当前状态有没有被搜索过。由于最大只有8192,所以数组是开得下的。
对于某状态的L和R,如果highbit(L)<=highbit(R),那么就把highbit(R)合并到左边,这样左右的合并就完成了
蛮好理解的(虽然我讲得不清不楚)
#include<bits/stdc++.h>
using namespace std;
#define R (sum[x]-L)
#define lowbit(x) x&-x
int n;
int a[10001];
bool flag;
int vis[1010][8195];
bool ans[10001];
int sum[10001];
int highbit[10001];
int sb;
void solve(int x,int L){//cout<<x<<" "<<L<<endl;if(highbit[L]<=highbit[R])L+=highbit[R];if(vis[x][L]==sb)return;vis[x][L]=sb;if(x==n){//cout<<L<<" "<<(lowbit(L))<<endl;if(L==(lowbit(L)))flag=true;return;}int xx=x+1;int l=(lowbit(L)),r=(lowbit(R));if(a[xx]<=l)ans[xx]=0,solve(xx,L+a[xx]);if(flag)return;if(!r||a[xx]<=r)ans[xx]=1,solve(xx,L);
}
void init(){for(int i=2;i<=8192;++i)highbit[i]=highbit[i>>1]+1;for(int i=1;i<=8192;++i)highbit[i]=1<<highbit[i];
}
void print(){for(int i=1;i<=n;++i){putchar((ans[i]?'r':'l'));}putchar('\n');
}
int main(){int T;scanf("%d",&T);//T=1;init();while(T--){memset(sum,0,sizeof(sum));memset(ans,0,sizeof(ans));flag=false;sb++;scanf("%d",&n);for(int i=1;i<=n;++i){scanf("%d",&a[i]);sum[i]=sum[i-1]+a[i];}//cout<<sum[n]<<endl;if(sum[n]!=(lowbit(sum[n]))){puts("no");continue;}solve(1,a[1]);if(flag){print();}else puts("no");}
}
Problem C: Subsequence Count
Time Limit: 1000 ms Memory Limit: 256 MB
Description
给定一个01串 S1⋯n 和 Q个操作。
操作有两种类型:
1、将 [l,r]区间的数取反(将其中的0变成1,1变成0)。
2、询问字符串 S的子串 Sl⋯r 有多少个不同的子序列。由于答案可能很大,请将答案对 10^9+7取模。
在数学中,某个序列的子序列是从最初序列通过去除某些元素但不破坏余下元素的相对位置(在前或在后)而形成的新序列。
Input
第一行包含两个整数 N 和 Q,分别表示字符串长度和操作次数。
第二行包含一个字符串 S。
接下来 Q行,每行3个整数 type,l,r ,其中 type 表示操作类型, l,r 表示操作区间为 [l,r] 。
Output
对于每一个 type=2 的询问,输出一个整数表示答案。由于答案可能很大,请将答案对 10^9+7 取模。
Sample Input
4 4
1010
2 1 4
2 2 4
1 2 3
2 1 4Sample Output11
6
8
HINT
对于5%的数据, N≤20,Q=1
对于10%的数据, N≤1000,Q=1
对于20%的数据, N≤10^5,Q≤10
对于另外30%的数据, 1≤N≤10^5,1≤Q≤10^5,type=2
对于100%的数据, 1≤N≤105,1≤Q≤105
Solution
求子串个数我们采用dp,设dp[i][0/1],代表dp到第i位,以0/1结尾的子串个数有几个
有
\(dp[i][s[i]]=dp[i-1][s[i]]+dp[i-1][!s[i]]+1,dp[i][!s[i]]=dp[i-1][!s[i]]\)
然后转成矩阵:
\[ if(s[i]==0)\left[ \begin{matrix} 1 & 0 & 0 \\ 1 & 1 & 0 \\ dp[i][0] & dp[i][1] & 1 \\ \end{matrix} \right] \]
\[ if(s[i]==1)\left[ \begin{matrix} 1 & 1 & 0 \\ 0 & 1 & 0 \\ dp[i][0] & dp[i][1] & 1 \\ \end{matrix} \right] \]
然后每次查询的话就是一段区间的矩阵乘起来,套个线段树维护一下
如果说是要区间反转0,1的话,直接把矩阵那几个元素交换一下位置好了
我可能写丑了,990ms擦着时限过去,考试的时候被卡常了QAQ
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod (long long)(1e9+7)
int read(){int num=0;char ch=getchar();while(!isdigit(ch)){ch=getchar();}while(isdigit(ch)){num=num*10+ch-'0';ch=getchar();}return num;
}
ll write(ll x){if(x<0){putchar('-');x=~(x-1);}ll s[20],top=0;while(x){s[++top]=x%10;x/=10;}if(!top)s[++top]=0;while(top)putchar(s[top--]+'0');putchar('\n');
}
struct matrix{ll a[3][3];matrix(){a[0][1]=a[0][2]=a[1][0]=a[1][2]=a[2][0]=a[2][1]=0;a[0][0]=a[1][1]=a[2][2]=1;}
};
matrix operator *(matrix a,matrix b){matrix c;memset(c.a,0,sizeof(c.a));for(int i=0;i<3;++i){for(int j=0;j<3;++j){for(int k=0;k<3;++k){c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod;}}}return c;
}
matrix val[400001];
int tag[400001];
char a[200001];
void build(int o,int l,int r){if(l==r){if(a[l]=='0'){val[o].a[1][0]=val[o].a[2][0]=1;}else val[o].a[0][1]=val[o].a[2][1]=1;return;}int mid=(l+r)/2;build(o*2,l,mid);build(o*2+1,mid+1,r);val[o]=val[o*2]*val[o*2+1];
}
void swaps(matrix &a){swap(a.a[0][0],a.a[0][1]);swap(a.a[1][0],a.a[1][1]);swap(a.a[2][0],a.a[2][1]);swap(a.a[0][0],a.a[1][0]);swap(a.a[0][1],a.a[1][1]);
}
void pushdown(int o){if(tag[o]){swaps(val[o*2]),swaps(val[o*2+1]);tag[o*2]^=1,tag[o*2+1]^=1;tag[o]=0;}
}
void update(int o,int l,int r,int L,int R){if(L<=l&&r<=R){tag[o]^=1;swaps(val[o]);return;}pushdown(o);int mid=(l+r)/2;if(L<=mid)update(o*2,l,mid,L,R);if(mid<R)update(o*2+1,mid+1,r,L,R);val[o]=val[o*2]*val[o*2+1];
}
matrix query(int o,int l,int r,int L,int R){if(L<=l&&r<=R){return val[o];}pushdown(o);int mid=(l+r)/2;matrix ret;if(L<=mid)ret=ret*query(o*2,l,mid,L,R);if(mid<R)ret=ret*query(o*2+1,mid+1,r,L,R);return ret;
}
int main(){int n,m;scanf("%d%d%s",&n,&m,a+1);build(1,1,n);while(m--){int opt=read(),l=read(),r=read();if(opt==1){update(1,1,n,l,r);}else {matrix tmp=query(1,1,n,l,r);write((tmp.a[2][1]+tmp.a[2][0])%mod);}}
}
转载于:https://www.cnblogs.com/youddjxd/p/11442067.html
[补档]noip2019集训测试赛(八)相关推荐
- [补档]noip2019集训测试赛(九)
因为这次考试我一道题都不会,所以先不写了 转载于:https://www.cnblogs.com/youddjxd/p/11442143.html
- [补档]noip2019集训测试赛(十)
Problem A: fibonacci Time Limit: 2000 ms Memory Limit: 256 MB Description 小y最近迷上了fibonacci数列,他定义了一种数 ...
- [补档]noip2019集训测试赛(十二)
Problem A: 记忆(memory) Time Limit: 1000 ms Memory Limit: 512 MB Description 你在跟朋友玩一个记忆游戏. 朋友首先给你看了n个长 ...
- [补档]noip2019集训测试赛(十三)
Problem A: Fairy Time Limit: 1000 ms Memory Limit: 256 MB Description 给定n个点,m条边的无向图(无自环),可以从图中删除一条边, ...
- [补档]noip2019集训测试赛(十四)
Problem A: Fibonacci(fib.pas/cpp) Time Limit: 1000 ms Memory Limit: 128 MB Description 豆豆最近迷上了Fibona ...
- [补档]noip2019集训测试赛(十五)
Problem A: 传送带 Time Limit: 1000 ms Memory Limit: 256 MB Description 在一个二维平面上有两条传送带,每一条传送带可以看成是一条线段.两 ...
- noip2019集训测试赛(五)
Problem A: lcm Time Limit: 1000 ms Memory Limit: 256 MB Sample Input 3 1 2 5 Sample Output 1 4 55 HI ...
- noip2019集训测试赛(七)
Problem A: Maze Time Limit: 1000 ms Memory Limit: 256 MB Description 考虑一个N×M的网格,每个网格要么是空的,要么是障碍物.整个网 ...
- 【2016北京集训测试赛(八)】 直径 (虚树+树的直径)
Description 注意:时限更改为4s 题解 考虑最原始的直径求法:找到离根节点(或离其他任意一点)最远的节点far1,再从far1出发找到离far1最远的节点far2,far1至far2的距离 ...
最新文章
- 一种用户-系统协同的概念模型
- golang单向散列函数
- gin中间件中使用Goroutines
- PHP之session与cookie
- MySQL(三)——函数、事务(ACID)、索引、权限管理和备份、数据库三大范式
- Linux系列开坑记(二)-神的编辑器Vim
- Python 私有变量的访问和赋值
- Sharepoint学习笔记---如何在Sharepoint2010网站中整合Crystal Report水晶报表(显示数据 二)...
- MVC教程第五篇:MVC整合Ajax
- Delphi使用经验笔记。
- mysql 转ascii_MySQL ascll()函数
- 1.5万字详述 | 全开源:python写小游戏+AI强化学习与传统DFS/BFS控制分别实现
- Python基础——正则表达式
- 计算机网络网络层之路由算法
- linux qt 触摸屏事件,利用触摸屏获取事件坐标
- Java基础2讲义四千字总结---黑马刘意
- 数字证书及CA的详细理解
- RedHat 自定义Jenkins Slaver Service,并开机自启动
- android手机怎么投屏到电视盒子,手机怎么投屏到电视?原来这么简单
- Linux——进程管理(crontab实例傻瓜教程)