The 2015 China Collegiate Programming Contest -ccpc-c题-The Battle of Chibi(hdu5542)(树状数组,离散化)
2015-11-06 22:09
393 查看
当时比赛时超时了,那时没学过树状数组,也不知道啥叫离散化(貌似好像现在也不懂)。百度百科——离散化,把无限空间中无限的个体映射到有限的空间中去,以此提高算法的时空效率。
这道题是dp题,离散化和树状数组用来优化,状态转移方程:dp[i][j]=sum(dp[i-1][k])----k需要满足a[j]>a[k]&&k<j;
i表示所要选的个数,j表示以第a[j]个数结尾所有的符合要求的递增串的个数,最后答案就是sum(dp
[j])--1<=j<=p;n 为要选的个数,p为所给数的总数,这个方程很容易想,这里不说了
(因为叫我说也说不清)。
数据肯定很大所以题目要求取模。
今天刚学树状数组还不太会用。
下面给出树状数组的模板
View Code
为什么要离散化呢,因为N的范围为1000,而所给元素a[i]的范围为1e+9;
用树状数组时开不了那么大的数组,所以要离散化,将所给的数对应到1000以内连续的数,这样不会改变每个数之间的大小关系。
那么树状数组就可以开bit[1005];最后复杂度为n2log(n);
下面给出代码
这道题是dp题,离散化和树状数组用来优化,状态转移方程:dp[i][j]=sum(dp[i-1][k])----k需要满足a[j]>a[k]&&k<j;
i表示所要选的个数,j表示以第a[j]个数结尾所有的符合要求的递增串的个数,最后答案就是sum(dp
[j])--1<=j<=p;n 为要选的个数,p为所给数的总数,这个方程很容易想,这里不说了
(因为叫我说也说不清)。
数据肯定很大所以题目要求取模。
今天刚学树状数组还不太会用。
下面给出树状数组的模板
//[1,n] int bit[MAX_N+1],n; int sum(int i) { int s=0; while(i>0) { s+=bit[i]; i-=i&-i; } return s; } void add(int i,int x) { while(i<=n) { bit[i]+=x; i==i&-i; } }
View Code
为什么要离散化呢,因为N的范围为1000,而所给元素a[i]的范围为1e+9;
用树状数组时开不了那么大的数组,所以要离散化,将所给的数对应到1000以内连续的数,这样不会改变每个数之间的大小关系。
那么树状数组就可以开bit[1005];最后复杂度为n2log(n);
下面给出代码
#include<stdio.h> #include<algorithm> #include<string.h> #include<stdlib.h> #include<iostream> #include<map> typedef long long ll; ll sum(int n); void add(int n,ll kk,int z); ll dp[1005][1005]; int a[1005]; int b[1005]; int bit[1005];//树状数组 const ll pp=1e9+7; using namespace std; int main(void) { int n,i,j,k,p,q; scanf("%d",&n); for(i=1; i<=n; i++) { map<int,int>my;//用来离散化的(将大的数转化1000以内的数) memset(dp,0,sizeof(dp)); for(j=0; j<=1000; j++) { dp[1][j]=1; }//当就选1个时全初始化1 scanf("%d %d",&p,&q); for(j=1; j<=p; j++) { scanf("%d",&a[j]); b[j]=a[j]; } sort(b+1,b+p+1);//离散化前的排序比如200 300 100 排完为100 200 300 那么对应为1 2 3 int c[1005]; int cnt=1; for(j=1; j<=p; j++) { if(j==1) { my[b[j]]=cnt; } else { if(b[j]!=b[j-1]) { cnt++; my[b[j]]=cnt; } else { my[b[j]]=cnt; } } } for(j=1; j<=p; j++) { a[j]=my[a[j]]; }//将原数组每个元素改为对应元素 200 100 300 -〉2 1 3 for(j=2; j<=q; j++)//要选的个数 { memset(bit,0,sizeof(bit)); for(k=j-1; k<=p; k++)//可以改成从1循不过时间长 { ll nn=sum(a[k]-1); dp[j][k]=nn; add(a[k],dp[j-1][k],cnt); } } ll endd=0; for(j=1; j<=p; j++) { endd=(endd+dp[q][j])%pp; } printf("Case #%d: ",i); printf("%lld\n",endd); } return 0; } ll sum(int n) { ll s=0; while(n>0) { s=(bit +s)%pp; n=n&(n-1); } return s; } void add(int n,ll kk,int z) { while(n<=z) { bit =(kk+bit )%pp; n+=(n&(-n)); } }
相关文章推荐
- 定界符是什么意思
- ActiveMQ消息中间件整合Java配置实例
- PhP之路
- java 内存分配小结
- 配置Log4j(很详细)
- 基于Python的机器学习实战:KNN
- java JFrame居中
- axis2 好文章
- cocos2dx-3.0(33) 中的缓存TextureCache、SPriteFrameCache、AnimationCache
- perf 工具介绍3
- This Android SDK requires Android Developer Toolkit version 23.0.0 or above
- 微软C# Process类的两个静态方法 存在内存泄露
- 代理和协议
- Android 快捷键
- 最长递增子序列详解(longest increasing subsequence)
- C中堆和栈的区别
- BLOck基本理解
- Daily Scrumming* 2015.11.6(Day 18)
- 配置ADT
- Daily Scrumming* 2015.11.5(Day 17)