NOIP模拟赛 t3 nan
来源:互联网 发布:lego ev3 编程 编辑:程序博客网 时间:2024/06/05 10:07
模拟赛的名字都好迷啊23333
nan
【问题描述】
我们有一个序列,现在他里面有三个数1,2,2 。我们从第三个数开始考虑:
1、第三个数是2,所以我们在序列后面写2个3,变成 1,2,2, 3, 3。
2、第四个数是3,所以我们在序列后面写3个4,变成 1, 2, 2, 3, 3, 4,4,4。
那么你可以看到,这个序列应该是 1,2,2,3,3,4,4,4,5,5,5,6,6,6,6,…。
如果我们设一个数x最后出现的位置为last(x),那么现在我希望知道 last(last(x))等于多少。
【输入格式】
第一行一个整数T,代表数据组数。
接下来T行每行一个整数x 。
【输出格式】
T行,每行一个整数,代表last(last(x))%(10^9+7) 的值。
【样例输入】
3
3
10
100000
【样例输出】
11
217
507231491
【样例解释】
╭︿︿︿╮
{/ o o /}
( (oo) )
︶︶︶
【数据规模与约定】
对于30% 的数据, 1<=x<=10^3。
对于60%的数据, 1<=x<=10^6。
对于100%的数据,1<=x<=10^9,1<=T<=2*10^3 。
考试的时候看到这道题内心窃喜,以为自己打表就可以过60%了。
然后。
数组简直怎么开都开不够啊,too large。最后还是只打了30分的表。
于是想尽了办法优化暴力(…)结果最后打表的程序根本交不上,早知道就把暴力交上去了还有30分。
题目分析:
如果对每个数x,直接存每个数的last,甚至是last(last(x)),无疑都是会爆空间的。考虑分区间来做。
对于原序列:
1,2,2,3,3,4,4,4,5,5,5,6,6,6,6,7,7,7,7,…
last[i]=1+2*2+3*2+…+(i-1)*num[i-1]+num[i];
其中num[i]表示这个数出现的次数
对于每个数字出现的次数再确定一个序列:
1,2,2,3,3,4,4,4,5,…
是不是特别神奇。。。
我们可以把出现次数相同的数划在同一个区间,则原序列可以划分为:
1|2,2,3,3,|4,4,4,5,5,5,|6,6,6,6,7,7,7,7,…
对第i个区间,数字出现的次数为i。
last[last[i]]其实就相当于求第二个序列(划分区间)后的last[i]。
[据大佬说暴力算一下最后跑1e9大概一百四十万个区间就够了,这样数组和时间复杂度都是可以接受的]
怎么求啊?
对于每个区间利用两个数组left,right,分别存储区间最左边的数和最右边的数。不难发现区间i最右边的数就是last[i]。
而last[i]其实可以转化为求和了,而且是等差求和。
我们可以维护一个前缀和表示区间1到区间i的和。但算的是每个区间,要回到原序列就还要再乘个数。
而输入的数n很有可能是在区间中间,而不是卡在区间的两端。
所以我们还要对n所在的区间里的和再处理。先二分找到n所在的区间,然后再利用等差求和处理区间内部。
为什么前缀和sum[i]对应的就是last[last[i]]?
还是看这个序列:
1,2,2,3,3,4,4,4,5,5,5,6,6,6,6,…
还是举栗子吧:last[3]=5,
而在num[i]的序列中:
(last[i]=sum[i])
1,2,2,3,3,4,4,4,5,5,5,6,6,6,6,…
5对应的那个数又是第二次出现的3 (这个是显然的,对任意都成立,根据这个数列的形成方式)
所以last[5]=sum[3];
所以last[last[i]]=sum[i]
具体看代码吧。
#include<cstdio>#include<cstring>#include<algorithm>#define ll long longusing namespace std;const int N = 1400000 + 10;const int mod = 1e9 + 7;int t;ll left[N],right[N];int temp;//有多少组 ll ans=0;ll sum[N];//求前缀和 int main(){ //freopen("nan.in","r",stdin); //freopen("nan.out","w",stdout); left[1]=1,right[1]=1; left[2]=2,right[2]=3; temp=2; for(int i=3;i<=N - 10;i++){ left[i]=right[i-1]+1; right[i]=right[i-1]+temp; if(i>=right[temp]) temp++;//已经到下一组了 } memset(sum,0,sizeof(sum)); for(int i=1;i<=N - 10;i++){ sum[i]=sum[i-1]+i*(right[i]-left[i]+1)*(left[i]+right[i])/2%mod; sum[i]%=mod; } scanf("%d",&t); while(t--){ int n; scanf("%d",&n); int i=lower_bound(left+1,left+N-9,n)-left-1; //二分查找是第几个区块 ans=sum[i-1]; ans+=(i)*(n-right[i-1])*(left[i]+n)/2%mod; printf("%I64d\n",ans%mod); } return 0;}
- NOIP模拟赛 t3 nan
- 【20160904】NOIP模拟赛T3
- noip模拟11.3 T3
- NOIP 模拟赛 nan (暴力?)
- [NOIP模拟]T3:系列维护
- 【NOIP模拟】 (10.24) T3 math
- noip 2017 模拟 D1 T3
- 【NOIP模拟】 (10.31) T3 纸带
- NOIP模拟赛 T3:与众不同(线段树+滑动窗口)
- nodgd 好路线 noip 2015 模拟赛 T3
- 【NOIP 模拟题】[T3] 约会(lca)
- NOIP模拟(10.19)T3 放盒子
- NOIP模拟(10.20)T3 裁剪表格
- NOIP模拟(20171023)T3 拆网线
- NOIP模拟(10.22)T3 树
- NOIP模拟(10.23)T3 拆网线
- NOIP模拟(10.24)T3 Math
- NOIP模拟(20171024)T3 数学
- 正则表达式--基础语法总结
- 【新】CentOS7部署Kubernetes集群
- Sublime Text SFTP 注册码
- Spark-core 架构及工作机制综述
- java的不同架构
- NOIP模拟赛 t3 nan
- 关于Mvc,Mvp,PureMvc
- Java 抽象类和接口
- C#ASV大宝,MD5 CANG加密算法 演示
- hilbert曲线用于空间索引
- Java对于面向对象编程的设计
- intel GPU加速在linux 上测试, 多路编码
- 数据库的约束
- 简书上使用markdown