HDU 5439 Aggregated Counting (2015年长春赛区网络赛C题)
来源:互联网 发布:月度m2数据 编辑:程序博客网 时间:2024/04/29 09:14
1.题目描述:点击打开链接
2.解题思路:本题利用打表+二分查找。仔细观察后会发现如下规律:
(1):序列中,相同元素的个数构成的序列仍然是原序列;
(2):如果我们按照个数来分类,可以写成下面的形式:
个数 元素
1 1
2 2, 3
3 4, 5
4 6, 7, 8
5 9, 10, 11
6 12, 13, 14, 15
7 16, 17, 18, 19
......
可以发现:1. sum[i]是个数为i的所有元素中最后一个元素;2.第i行中的所有元素也是i这个元素在原始序列中的所有下标。
(3)观察sum{i*a[i]}可以发现,这个计算结果就是我们要的答案。因此可以考虑计算第n项对应的元素a[n],然后求sum{i*a[i]|1<=i<=n}即可。
那么第一个问题就是,已知n,如何获得a[n]?考虑到第n项对应的元素a[n]不是很大,可以事先测试一下当n是多少的时候,sum[n]刚好超过10^9,经过试验会发现,N=440000即可。这样,可以事先打表所有前N项的元素。由于sum数组也可以理解为当个数为i时候,已经写了几个不同的数。那么我们可以找一下n在sum中的下标,即k=lower_bound(sum+1,sum+N,n)-sum。这样,我们就可以找到个数为k-1时候的最后一个元素,即sum[k-1](规律2第一条的应用)。同时,根据规律(2)的第二条还可以知道,第n项的元素其实就是k。
那么第二个问题就是,如何高效计算sum{i*a[i]},因为i最大可以达到10^9,遍历一遍肯定会超时,但是仔细观察后会发现,当a[i]固定时候,所有的i其实构成了一个等差数列,这其实还是规律2第二条的应用:a[i]的所有下标显然是一个公差为1的等差数列,而且个数恰好是a[i]个,因此,就可以用O(1)时间计算出a[i]对应的这段等差数列的和,然后再和a[i]相乘。而这个过程也是可以预先打表处理的。不妨用S[i]表示前i项乘积和的结果。这样,最终的答案ans=S[k-1]+k*sum{i|sum[k-1]+1<=i<=n}。注意,最后一段之所以不用等差数列公式求解是因为中间结果可能会爆long long,但考虑到这段的个数只有不超过4000个,可以直接逐项相加取模。
3.代码:
#include<iostream>#include<algorithm>#include<cassert>#include<string>#include<sstream>#include<set>#include<bitset>#include<vector>#include<stack>#include<map>#include<queue>#include<deque>#include<cstdlib>#include<cstdio>#include<cstring>#include<cmath>#include<ctime>#include<cctype>#include<complex>#include<functional>#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;#define me(s) memset(s,0,sizeof(s))#define rep(i,n) for(int i=0;i<(n);i++)typedef long long ll;typedef unsigned int uint;typedef unsigned long long ull;typedef pair <int, int> P;const int N=440000+10;const int MOD=1000000007;int a[N];ll sum[N]; //sum[i]表示序列前i项的和ll S[N];//S[i]表示前i项的乘积和void init(){ a[1]=1,a[2]=2;a[3]=2; int cnt=4; for(int i=3;i<N;i++) { for(int j=0;j<a[i];j++) a[cnt++]=i; if(cnt>=N)break; } sum[0]=0; for(int i=1;i<N;i++) sum[i]=sum[i-1]+a[i]; S[0]=0; ll first=1; for(int i=1;i<N;i++) { ll s=first*a[i]%MOD+(a[i]-1)*a[i]/2; s%=MOD; S[i]=(S[i-1]+s*i)%MOD; first=(first+a[i])%MOD; }}int main(){ int T; init(); scanf("%d",&T); while(T--) { int n; scanf("%d",&n); int k=lower_bound(sum+1,sum+N,n)-sum; ll last=sum[k-1]; ll val=k; ll ans=0; for(int i=last+1;i<=n;i++)//逐项相加来求解最后一段的和 ans=(ans+i)%MOD; ans=ans*val%MOD; ans=(ans%MOD+S[k-1])%MOD; printf("%d\n",ans); }}
- HDU 5439 Aggregated Counting (2015年长春赛区网络赛C题)
- HDU 5439. Aggregated Counting (2015长春网络赛C题)
- 2015长春网络赛1003 HDU 5439 Aggregated Counting
- HDU 5446 Unknown Treasure (2015年长春赛区网络赛J题)
- HDU 5441 Travel (2015年长春赛区网络赛E题)
- HDU 5438 Ponds (2015年长春赛区网络赛B题)
- HDU 5437 Alisha’s Party (2015年长春赛区网络赛A题)
- HDU 5445 Food Problem (2015年长春赛区网络赛I题)
- HDU 5447 Good Numbers (2015年长春赛区网络赛K题)
- HDU 5442 Favorite Donut (2015年长春赛区网络赛F题)
- HDU 5439 Aggregated Counting
- HDU 5439 Aggregated Counting
- HDU 5439 Aggregated Counting
- hdu 5439 Aggregated Counting
- hdu 5439 Aggregated Counting 2015长春网络赛 分块 二分 预处理
- hdu 5439 Aggregated Counting(长春网络赛——找规律+二分)
- hdu 5439 Aggregated Counting(规律)
- HDU 5439 Aggregated Counting(数论+二分)
- LeetCode 11 容器盛水问题
- HDU 1335 Basically Speaking
- 人生重要的道路:软工
- 海选女主角
- Android Studio的下载及安装
- HDU 5439 Aggregated Counting (2015年长春赛区网络赛C题)
- 【A/B%m+扩展欧几里得】hdu 1576 A/B
- 0916Android基础自定义View进度条专题
- 读《“问题导学”模式英语学习兴趣的培养》有感
- Java基础语法——运算符、流程控制语句、if条件语句
- js如何判断 有中文的字符串的长度?
- Firefox 插件用法备忘
- Android第九讲——网络(三)HttpClient
- 如何抢努比亚z9 max