小X归来 模拟赛1 解析
Problem1 单峰
小X 归来后,首先对数列很感兴趣。他想起有1类特殊的数列叫单峰数列。 我们说一个数列 {ai} 是单峰的,当且仅当存在一个位置 k 使得 ai < ai+1(i < k) 且 ai > ai+1(i ≥ k)。 现在小X 想知道,对于 1 到 n 的所有排列,其中有多少个是单峰数列。 Input 第1行包含1个整数 n。 Output 第一行包含一个整数,表示答案除以 1e9 + 7 的余数。 Example
unimodal.in | unimodal.out |
2 | 2 |
Scoring • 对于 20% 的数据, n ≤ 10。 • 对于 50% 的数据, n ≤ 105。 • 对于 100% 的数据, 2 ≤ n ≤ 1018。
解析:
1.1 20 分做法
生成所有全排列并判断,时间复杂度 O(n · n!)。
1.2 50 分做法
根据排列组合可以发现,峰顶一定是 n,因此考虑 1 ∼ n - 1 分别放在 n 的左边还是右边,一一得出相应
的唯一方案。所以答案就是 2^(n-1),时间复杂度 O(n)。
1.3 100 分做法
对2^(n-1)用快速幂即可,时间复杂度 O(log n)。
代码:
#include<bits/stdc++.h>
using namespace std;
template <class T>
inline void readl(T &x)
{ x=0;bool f=0;char ch=getchar();
while(!isdigit(ch)) { f=(ch==45);ch=getchar();}
while( isdigit(ch)) { x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?(~x+1):x;}
long long n;
const int md=1e9+7;
inline long long bpow(long long a,long long b)
{ long long base=a;
long long ans=1;
while(b)
{
if(b&1) ans=(ans%md*base%md)%md;
base=base*base%md;
b>>=1;
}
return ans%md;
}
int main()
{ freopen("unimodal.in","r",stdin);
freopen("unimodal.out","w",stdout);
readl(n);
printf("%lld\n",(bpow(2,n-1)%md));
return 0;
}
Problem2 积木
小X 感到很无聊,从柜子里翻出了他小时候玩的积木, 这套积木共有 n 块,每块积木都是1个长方体。小X 想用这些积木拼成1个积木塔(不必每块 积木都使用, 所谓积木塔,就是将积木1个1个摞起来,(除去最底层的积木外)每块积木的底下必须能被它下面 的积木的底面完全包含(即对应的长宽都要更小或相等)。当然,积木可以任意放置,即可以以任意一面 作为底面。 现在小X 想知道,积木塔最大能拼多高。 Input 第⼀⾏包含⼀个整数 n。 接下来 n ⾏,每⾏包含三个整数 a; b; c,表⽰该块积木是⼀个 a × b × c 的长⽅体。 Output 第⼀⾏包含⼀个整数,表⽰答案。 Example
brick.in | brick.out |
3 8 7 6 3 9 4 1 10 5 |
18 |
Explanation 选择第 1 块积木和第 3 块积木。
Scoring • 对于 10% 的数据, n = 1。
• 对于 40% 的数据, n ≤ 6。
• 对于 100% 的数据, 1 ≤ n ≤ 15, 1 ≤ a; b; c ≤ 108。
解析:
2.1 10 分做法
输出 maxfa; b; cg。
2.2 40 分做法
生成全排列,然后枚举每个积木哪个面朝上,时间复杂度 O(n! · 3n)。
2.3 100 分做法
显然是状态压缩 DP。设计状态 f[S][i][0/1/2] 表示已经用了集合 S 内的积木,最顶上是编
号为 i 的积木,它的哪个面朝上。转移时枚举不在 S 内的积木,以及朝上的面判断即可。时间
复杂度 O(2n · (3n)2)。
PS:但是这道题的数据有点弱,只要搜索写得好,照样可以过。
代码:
1.DP
#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
int readl()
{
int x=0,fg=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')fg=-fg;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*fg;
}
int n,a[200],b[200],c[200],t[20],mx=-100,bin[200];
ll ans=-100;
ll f[(1<<15)+10][16][3];
int main()
{
freopen("brick.in","r",stdin);
freopen("brick.out","w",stdout);
n=readl();
for(int i=1;i<=n;i++)
{
a[i]=readl();b[i]=readl();c[i]=readl();
t[1]=a[i];t[2]=b[i];t[3]=c[i];
sort(t+1,t+4);
a[i]=t[1];b[i]=t[2];c[i]=t[3];
mx=max(mx,t[3]);
}
if(n==1){printf("%d",mx);return 0;}
bin[1]=1;
for(int i=2;i<=20;i++)bin[i]=bin[i-1]*2;
for(int i=1;i<=n;i++)
{
f[bin[i]][i][0]=a[i];
f[bin[i]][i][1]=b[i];
f[bin[i]][i][2]=c[i];
}
//printf("%lld %lld %lld\n",f[1][1][0],f[1][1][1],f[1][1][2]);
for(int x=0;x<(1<<n);x++)
for(int i=1;i<=n;i++)
{ if(x&bin[i])continue;
for(int j=1;j<=n;j++)
{
if((x&bin[j])==0)continue;
int s=x|bin[i];
if(b[j]>=b[i]&&c[j]>=c[i])f[s][i][0]=max(f[x][j][0]+a[i],f[s][i][0]);
if(c[j]>=c[i]&&a[j]>=b[i])f[s][i][0]=max(f[s][i][0],f[x][j][1]+a[i]);
if(b[j]>=c[i]&&a[j]>=b[i])f[s][i][0]=max(f[s][i][0],f[x][j][2]+a[i]); if(c[j]>=c[i]&&b[j]>=a[i])f[s][i][1]=max(f[s][i][1],f[x][j][0]+b[i]);
if(c[j]>=c[i]&&a[j]>=a[i])f[s][i][1]=max(f[s][i][1],f[x][j][1]+b[i]);
if(b[j]>=c[i]&&a[j]>=a[i])f[s][i][1]=max(f[s][i][1],f[x][j][2]+b[i]); if(c[j]>=b[i]&&b[j]>=a[i])f[s][i][2]=max(f[s][i][2],f[x][j][0]+c[i]);
if(c[j]>=b[i]&&a[j]>=a[i])f[s][i][2]=max(f[s][i][2],f[x][j][1]+c[i]);
if(b[j]>=b[i]&&a[j]>=a[i])f[s][i][2]=max(f[s][i][2],f[x][j][2]+c[i]);
ans=max(ans,max(f[s][i][0],max(f[s][i][1],f[s][i][2])));
//printf("%d %d %d %d ***\n",x,s,i,j);
//printf("%lld %lld %lld\n",f[s][i][0],f[s][i][1],f[s][i][2]);
}
}
printf("%lld",ans);
fclose(stdin);fclose(stdout);
return 0;
}
2.DFS
#include<bits/stdc++.h>
using namespace std;
template <class T>
inline void readl(T &x)
{ x=0;bool f=0;char ch=getchar();
while(!isdigit(ch)) { f=(ch==45);ch=getchar();}
while( isdigit(ch)) { x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?(~x+1):x;} int n,maxn=0;
bool vis[1001];
struct node
{ int mx,h[4],x[4],y[4];}e[100];
void dfs(int H,int x,int y)
{ maxn=max(maxn,H);
for(register int i=n;i>=1;i--)
if(!vis[i])
{ vis[i]=1;
for(register int j=1;j<=3;j++)
if(e[i].x[j]<=x&&e[i].y[j]<=y)
dfs(H+e[i].h[j],e[i].x[j],e[i].y[j]);
vis[i]=0;
}
}
int main()
{ freopen("brick.in","r",stdin);
freopen("brick.out","w",stdout);
readl(n);
for(register int i=1,x,y,z;i<=n;i++)
{ readl(x);readl(y);readl(z);
e[i].mx=max(x,max(y,z));
e[i].x[1]=min(x,y);e[i].y[1]=max(x,y);e[i].h[1]=z;
e[i].x[2]=min(y,z);e[i].y[2]=max(y,z);e[i].h[2]=x;
e[i].x[3]=min(x,z);e[i].y[3]=max(x,z);e[i].h[3]=y;
}
if(n==1){printf("%d",e[1].mx);return 0;}
for(int i=1;i<=n;i++)
{ vis[i]=1;
for(int j=1;j<=3;j++)
dfs(e[i].h[j],e[i].x[j],e[i].y[j]);
vis[i]=0;
}
printf("%d",maxn);
return 0;
}
Problem3 同余
小X 望着草稿纸上的数列,结合自己对同余的粗浅认识,又想到了个新问题。 对于1个长度为 n 的数列 {ai},每次询问将给出1组数 l; r; p; q,小X 想知道有多少个 i 满足 l ≤ i ≤ r 且 ai ≡ q (mod p)。 小X 沉迷这个问题,因此一共进行了 m 次询问。 Input 第⼀⾏包含两个整数 n; m。 第⼆⾏包含 n 个整数,表⽰数列 faig。 接下来 m ⾏,每⾏包含四个整数 l; r; p; q,表⽰⼀次询问。 Output m ⾏,每⾏包含⼀个整数,表⽰该次询问的答案。 Example
congruence.in | congruence.out |
5 2 1 5 2 3 7 1 3 2 1 2 5 3 0 |
2 1 |
Scoring • 对于 20% 的数据, ai ≤ 1。
• 对于 60% 的数据, ai ≤ 100。
• 对于 100% 的数据, 1 ≤ m ≤ 105, 1 ≤ l ≤ r ≤ n ≤ 105, 0 ≤ q < p ≤ 10000, 0 ≤ ai ≤ 10000。
解析:
3.1 20 分做法
ai 6 1,因此转变为求区间内 0 和 1 的个数,用前缀和优化,注意 p = 1 的情况。时间复杂
度 O(n + m)。
3.2 60 分做法
同上面,用至多 101 个前缀和即可,时间复杂度 O(ai(n + m))。
3.3 100 分做法
观察到,其实要求的是某一范围内 kp + q 的个数,当 p 较大时, k 的取值范围很小。不妨
设“较大”的界限是 > K。
考虑将问题拆开来并排序,这样每个问题就变成了询问 1 ∼ r 中有多少个 kp + q。维护⼀
个哈希数组, h[i] 表示 i 有多少个;以及⼀个模数数组 g[i][j],表示模 i 为 j 有多少个。
每次指针向右移,直到移动到当前询问的位置,每移一次就将这个数分别在两个数组内标
记,复杂度总体是 O (nK)。
每次询问时,对于较小的 p 直接在 g 中查询,对于较⼤的 p 枚举 k 并在 h 中查询。
可以看出 K = √ai = 100 时最优。
代码:
1.100分
#include<bits/stdc++.h>
using namespace std;
template <class T>
inline void readl(T &x)
{ x=0;bool f=0;char ch=getchar();
while(!isdigit(ch)) { f=(ch==45);ch=getchar();}
while( isdigit(ch)) { x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?(~x+1):x;}//读入优化 int n,m;
int a[100100],sum[100100],ans[100100];
struct range
{ int r,id,p,q,opt;}e[100100<<1];//注意开两倍的空间
int maxn=0;
int cmp(range a,range b)
{ return a.r<b.r;}
int main()
{ freopen("congruence.in","r",stdin);
freopen("congruence.out","w",stdout);
readl(n);readl(m);
for(int i=1;i<=n;i++)
readl(a[i]);
for(int i=1,l,r,p,q;i<=m;i++)
{ readl(l);readl(r);readl(p);readl(q);
e[i].r=l-1; e[i].id=i; e[i].p=p; e[i].q=q; e[i].opt=-1;//需要计算sum[r]-sum[l-1]
e[i+m].r=r;e[i+m].id=i;e[i+m].p=p;e[i+m].q=q;e[i+m].opt=1;//将左右两边分开计算,将无序的提问变为线性的区间计算
}
sort(e+1,e+1+2*m,cmp);
int tail=0;//解析中的指针
for(int i=1;i<=2*m;i++)
{ while(tail<e[i].r)
{ tail++;
sum[a[tail]]++;//将所有的数字出现的个数都统计一遍
maxn=max(maxn,a[tail]);//统计最大值,方便确定下文kp+q的界限
}
for(int j=0;j*e[i].p+e[i].q<=maxn;j++)//解析中的kp+q
ans[e[i].id]+=sum[j*e[i].p+e[i].q]*e[i].opt;//e[i].id表示询问的序号,如果opt=-1就代表左界限,乘积为负代表减去[1,l-1]的值,opt=1同理
}
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);//输出答案
return 0;
}
2.60分(重点是理解40%的前缀和写法)
#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
int readl()
{
int x=0,fg=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')fg=-fg;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*fg;
}
int n,m,a[101000],s[101000],v[100010][101];
int ac[101000];
int calc(int l,int r,int p,int q)
{
int ret=0;
for(int i=l;i<=r;i++)
if(a[i]%p==q%p)ret++;
return ret;
}
int main()
{
freopen("congruence.in","r",stdin);
freopen("congruence.out","w",stdout);
n=readl();m=readl();
int bo=0;
for(int i=1;i<=n;i++)
{
a[i]=readl();if(a[i]>1)bo=1;
}
int ans,l,r,p,q;
if(n<=5010&&m<=5010)
{
for(int i=1;i<=m;i++)
{
l=readl();r=readl();p=readl();q=readl();
printf("%d\n",calc(l,r,p,q));
}
return 0;
}
if(bo==0)
{
for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i];
for(int i=1;i<=m;i++)
{
l=readl();r=readl();p=readl();q=readl();
if(p==1){ans=r-l+1;printf("%d\n",ans);continue;}
if(q%p==0)ans=r-l+1-s[r]+s[l-1];
if(q%p==1)ans=s[r]-s[l-1];
if(q%p>1)ans=0;
printf("%d\n",ans);
}
return 0;
}
for(int i=1;i<=n;i++)//重点
for(int j=0;j<=100;j++)
{
v[i][j]=v[i-1][j];
if(a[i]==j)v[i][j]++;
}
for(int i=1;i<=m;i++)
{
l=readl();r=readl();p=readl();q=readl();ans=0;
if(p==1){ans=r-l+1;printf("%d\n",ans);continue;}
ac[0]=0;
for(int i=0;i<=100;i++)
if(i%p==q%p)ac[++ac[0]]=i;
for(int i=1;i<=ac[0];i++)
ans=ans+v[r][ac[i]]-v[l-1][ac[i]];
printf("%d\n",ans);
}
fclose(stdin);fclose(stdout);
return 0;
}
小X归来 模拟赛1 解析的更多相关文章
- CONTEST36 小Z的模拟赛(2)
A.小Z的可恶路障 题目:http://www.luogu.org/problem/show?pid=U126 题解:暴力也可以过吧.我为了保险先求了一次最短路,然后枚举这条最短路上的所有边... 代 ...
- 小奇模拟赛9.13 by hzwer
2015年9月13日NOIP模拟赛 by hzwer (这是小奇=> 小奇挖矿(explo) [题目背景] 小奇要开采一些矿物,它驾驶着一台带有钻头(初始能力值w)的飞船,按既定路线依次飞 ...
- 【20170521校内模拟赛】热爱生活的小Z
学长FallDream所出的模拟赛,个人感觉题目难度还是比较适中的,难度在提高+左右,可能比较接近弱省省选,总体来讲试题考查范围较广,个人认为还是很不错的. 所有试题如无特殊声明,开启-O2优化,时限 ...
- Java 第十一届 蓝桥杯 省模拟赛 小明的城堡
小明用积木搭了一个城堡. 为了方便,小明在搭的时候用的是一样大小的正方体积本,搭在了一个 n 行 m 列的方格图上,每个积木正好占据方格图的一个小方格. 当然,小明的城堡并不是平面的,而是立体的.小明 ...
- Java 第十一届 蓝桥杯 省模拟赛 小明植树(DFS)
小明植树 题目 问题描述 小明和朋友们一起去郊外植树,他们带了一些在自己实验室精心研究出的小树苗. 小明和朋友们一共有 n 个人,他们经过精心挑选,在一块空地上每个人挑选了一个适合植树的位置,总共 n ...
- [GRYZ]寒假模拟赛
写在前面 这是首次广饶一中的OIERS自编自导,自出自做(zuo)的模拟赛. 鉴于水平气压比较低,机(wei)智(suo)的WMY/XYD/HYXZC就上网FQ下海找了不少水(fei)题,经过他们优( ...
- NOIP模拟赛20161022
NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...
- NOIP第7场模拟赛题解
NOIP模拟赛第7场题解: 题解见:http://www.cqoi.net:2012/JudgeOnline/problemset.php?page=13 题号为2221-2224. 1.car 边界 ...
- NOIP模拟赛 by hzwer
2015年10月04日NOIP模拟赛 by hzwer (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...
随机推荐
- python之socket编写
Socket 类型 套接字格式: socket(family,type[,protocal]) 使用给定的地址族.套接字类型.协议编号(默认为0)来创建套接字. socket类型 描述 socket. ...
- python入门-列表
列表使用[]来标识 列表和PHP中的数组类似 包括使用和访问方式都是类似 可以用下标索引的方式直接访问 来几个例子,这样看起来才舒服 names = ['baker','pitty','david', ...
- windows10系统右键添加cmd命令
https://blog.csdn.net/Mr_BEelzebub/article/details/78776104 首先,在桌面新建一个文本文档. Windows Registry Editor ...
- 5. jdk路径配置
path , classpath 的配置及作用? 1) PATH环境变量.作用是指定命令搜索路径,在i命令行下面执行命令如javac编译java程序时,它会到PATH变量所指定的路径中查找看是否能找到 ...
- vue之回车触发表单提交
vue之回车触发表单提交 操作: 在From标签中添加: @keyup.enter.native="handleSubmit" 注意: 1.若添加在Input标签上,只有聚焦在该i ...
- Simple2D-14(音乐播放器)简介
接下来文章中,会介绍一个简单的程序——音乐播放器.通过编写一个音乐播放器在 Simple2D 中加入两个库:音频库 bass 和界面库 ImGui. 下面是音乐播放器的预览图: 播放器的功能比较简单, ...
- Oracle 11g超详细安装步骤
一.首先是Oracle的安装 软件请自行到网上下载 18.等待,出现选择项时点击next 二.打开服务 三.验证数据库是否安装成功
- cobbler配置解析
1.Cobbler命令说明: 命令名称 命令用途 cobbler check 检查cobbler配置 cobbler list 列出所有的cobbler元素 cobbler report 列出元素的详 ...
- intelij创建MapReduce工程
1.创建一个maven工程 2.POM文件 <?xml version="1.0" encoding="UTF-8"?><project xm ...
- 机房servlet过滤器
1.源代码 loginform.html <html> <head> <title>使用过滤器改变请求编码</title> <meta http- ...