【比赛】2022.11.24 NOIP模拟赛
A. 不降序列
题目描述
lzx2005
了解到有一种在
维护一个序列 lzx2005
把原序列弄丢了,只留下序列 lzx2005
只记得原序列的长度为 lzx2005
希望找到一个满足要求的原序列,或者发现自己算错了。 众所周知,lzx2005
喜欢咕咕咕,请你帮帮他。
输入格式
从文件 lis.in
中读入。
第一行三个正整数
第二行
输出格式
输出到文件 lis.out
中。
第一行输出一个字符串,表示是否存在这样的原序列:如果存在,那么输出 Yes
,否则输出 No
。
如果存在这样的原序列,则你还需要输出第二行:
样例输入
4 10 3 3 7 7
样例输出
Yes 3 7 10 7
数据范围
对于全部数据,
subtask1(20)
subtask2(20)
subtask3(25)
subtask4(20)
subtask5(15)
无特殊限制。
分析
B. 分组问题
问题描述
小 X 的班级有
如果同一个小组中学生的学习进度相差过大,那么速度快的学生会产生一定的不满,同时会给速度慢的学生带来压力。因此一个组的不和谐度为这个小组成员间学习速度的极差,也就是小组中最大的
小 X 想要知道,一共有多少种不同的分组方式,可以使得分组后所有组的不和谐度之和不超过
但是小 X 并不会,请你帮帮他。因为答案可能很大,所以小 X 只要你求出方案数对
注: 小 X 认为两个分组方式不同,当且仅当存在一对学生,他们在一种分组方式中在同一组而在另一种方式中不在同一组。
输入格式
从文件 divide.in
中读入。
第一行两个整数
第二行
输出格式
输出到文件 divide.out
中。
输出一行一个整数表示方案数对
样例输入
4 5 1 3 5 7
样例输出
9
数据范围
对于所有测试数据,
子任务 1(20 分):
子任务 2(15 分):
子任务 3(15 分):不同的
子任务 4(20 分):
子任务 5(30 分):无特殊限制。
C. 变换问题
问题描述
你有一个数组
注意这里我们认为数组首尾是相邻的,也就是认为
问对于每个 -1
。
输入格式
从文件 trans.in
中读入。
第一行两个整数
第二行
输出格式
输出到文件 trans.out
中。
一行
样例输入
7 5 2 5 1 1 2 3 2
样例输出
5 5 7 -1 6
数据范围
对于
对于
对于
对于
D. 第四道题
问题描述
Alice和 Bob 进行一个填数的游戏。
Alice 问 Bob 有多少个序列
Alice 觉得这太简单了,又加了额外
答案对
输入格式
从文件 fourth.in
读入。
第一行三个正整数
接下来
输出格式
输出到文件 fourth.out
中。
一行一个整数表示答案。
样例输入
8 8 3 1 5 1 6 8 2 2 6 2 3 7 1 1 3 3 4 8 1 5 6 3 1 8 2
样例输出
5291
数据范围
subtask1(10)
subtask2(20)
subtask3(20)
subtask4(10)
;
subtask5(10)
subtask6(30)
无特殊限制;
对于
官方题解(再附上我的代码,如果订正过的话)
T1 不降序列
首先,如果
那么现在可以看成是在
#include<bits/stdc++.h> #define N 300005 using namespace std; int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } int n,m,k,tot; int a[N],b[N],B[N],cnt[N],sum[N]; int main(){ freopen("lis.in","r",stdin); freopen("lis.out","w",stdout); n=read(),m=read(),tot=k=read(); for(int i=1;i<=k;++i) B[i]=b[i]=read(); tot=unique(B+1,B+1+tot)-B-1; for(int i=1;i<=k;++i){ b[i]=lower_bound(B+1,B+1+tot,b[i])-B,cnt[b[i]]++; } for(int i=1;i<=tot;++i) sum[i]=sum[i-1]+cnt[i]; B[tot+1]=1e9+1; int v=m,pos=1; while(pos<=n-k&&v>B[1]){ int x=lower_bound(B+1,B+2+tot,v)-B; if(v<=B[x]) x--; for(int i=pos;i<=min(pos+sum[x]-1,n-k);++i) a[i]=v; v--; pos=pos+sum[x]; } if(pos<=n-k){return printf("No\n"),0;} printf("Yes\n"); for(int i=1;i<=k;++i) a[n-k+i]=B[b[i]]; for(int i=1;i<=n;++i) printf("%d ",a[i]);printf("\n"); fclose(stdin); fclose(stdout); return 0; }
T2 分组问题
为了避免变量重名,题面里的
把题目给出的 数组看成数轴上的
可以将原问题模型转化为:在数轴上选出若干条线段(可以退化成点),线段端点必须为给定的
于是我们有一个 DP:
不难发现,
转移有下面几种情况:
(1)
(2) 为新建的一条退化成点的线段:
(3) 作为左端点,即新建一条线段:
(4) 作为右端点,这时需要决定
答案为
时间复杂度
#include<bits/stdc++.h> #define mod 1000000007 #define int long long #define N 505 #define K 1005 using namespace std; int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } int n,m,ans; int a[N]; int f[2][N][K]; void add(int &a,int b){ a+=b;a%=mod; } signed main(){ // freopen("divide.in","r",stdin); // freopen("divide.out","w",stdout); n=read(),m=read(); for(int i=1;i<=n;++i) a[i]=read(); sort(a+1,a+1+n); f[0][0][0]=1; for(int i=0;i<n;++i){ int now=i&1; for(int j=0;j<=i+1&&(j<<1)<=n;++j) for(int k=0;k<=m;++k) f[now^1][j][k]=0; for(int j=0;j<=i&&(j<<1)<=n;++j){ for(int k=0;k<=m;++k){ int d=(a[i+1]-a[i])*j+k; if(d>m) break; add(f[now^1][j][d],f[now][j][k]*j); //i+1 不作为端点 add(f[now^1][j+1][d],f[now][j][k]); //自成一组 add(f[now^1][j][d],f[now][j][k]); //作为左端点 if(j>=1) add(f[now^1][j-1][d],f[now][j][k]*j); //作为右端点 } } } for(int i=0;i<=m;++i) add(ans,f[n&1][0][i]); printf("%lld\n",ans); // fclose(stdin); // fclose(stdout); return 0; }
T3 变换问题
对于每一个 1
,等于 0
,小于 -1
。
不难发现被
对于 0 -1 -1
或者 0 1 1
这样的三元组,只需要一次操作就可以使中间的数变成 0
。而对于 0 1 -1
这样的三元组,还额外需要一次操作才能使中间的数变成 0
。
进一步观察发现,如果存在 1 -1 1
这样 -1
和 1
交错的三元组,我们可以通过先对中间的数进行一次操作来使额外的两次操作减少到一次。
容易发现,额外的操作次数实际上可以这样计算:把原序列划分成若干段极长的 -1
和 1
交错的段,额外的操作次数就是这些段的长度除以二下取整的总和。
考虑顺序枚举 set
维护 -1
和 1
交错的极长段,时间复杂度
只会60分的暴力,QWQ。
T4 第四道题
首先如果存在两个限制
我们记
发现若存在两个限制的区间相交且颜色相同,那么这两个限制是可以同时不满足的。也就是说如果仅仅按上述减去不合法的方案的话,这两个限制同时不满足的方案数会被多减。 实际上我们要容斥,即枚举集合
记
- 将所有限制按右端点升序排,
由排序之后的前 个限制中的若干个组成。 中的限制的右端点均小于等于 。 中的限制的颜色均为 。 显然有递推式: 。
对每种颜色开一棵动态开点线段树即可维护。 假设
不会,QWQ。
本文作者:南风未起
本文链接:https://www.cnblogs.com/jiangchen4122/p/17419339.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步