【解题报告】13级个人结业赛(一) ——涨姿势专场

A.优化(1)

前缀和优化。

预处理出a数组0~i的和,然后每次取b[i]~i的和时取出sum[i]-sum[b[i]-1]。

 1 #include<stdio.h>
 2 #include<math.h>
 3 #include<string.h>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<map>
 7 #include<set>
 8 #include<queue>
 9 #include<stack>
10 using namespace std;
11 typedef long long ll;
12 ll f2(ll a[],ll b[],ll len)
13 {
14     ll ans=0,i,j;
15     for(i=0;i<len;i++)
16     {
17         if(i!=0) a[i]+=a[i-1];
18         if(b[i]!=0) ans+=a[i]-a[b[i]-1];
19         else ans+=a[i];
20     }
21     return ans;
22 }
23 ll a[1000005],b[1000005],len;
24 int main()
25 {
26     int i;
27     while(scanf("%lld",&len)!=EOF)//len<1000000
28     {
29         for(i=0;i<len;i++) scanf("%lld",&a[i]);//-1000000000<=a[i]<=1000000000
30         for(i=0;i<len;i++) scanf("%lld",&b[i]);//0<=b[i]<=i
31         printf("%lld\n",f2(a,b,len));
32     }
33     return 0;
34 }
View Code

B.优化(2)

离线处理。读入所有的点和查询,按x坐标排序,然后从小到大维护最大y。碰到点时更新最大y,碰到查询时将查询结果保存起来。处理完所有查询后按原来输入的顺序输出答案。

 1 #include<stdio.h>
 2 #include<math.h>
 3 #include<string.h>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<map>
 7 #include<set>
 8 #include<queue>
 9 #include<stack>
10 #define FOR(i,n) for(i=0;i<(n);i++)
11 #define CLR(a) memset(a,0,sizeof(a))
12 #define CIN(a) scanf("%d",&a)
13 typedef long long ll;
14 using namespace std;
15 pair<int,int> a[200005];
16 int ans[100005];
17 int main()
18 {
19     int n,q,i,x;
20     while(scanf("%d",&n)!=EOF)
21     {
22         for(i=0;i<n;i++) scanf("%d%d",&a[i].first,&a[i].second);
23         scanf("%d",&q);
24         for(i=1;i<=q;i++)
25         {
26             scanf("%d",&a[n].first);
27             a[n].second=-i;
28             n++;
29         }
30         sort(a,a+n);
31         int an=-1;
32         for(i=0;i<n;i++)
33         {
34             if(a[i].second<0) ans[-a[i].second]=an;
35             else an=max(an,a[i].second);
36         }
37         for(i=1;i<=q;i++)
38         {
39             printf("%d\n",ans[i]);
40         }
41     }
42     return 0;
43 }
View Code

C.优化(3)

详看代码。 

 1 #include<stdio.h>
 2 #include<math.h>
 3 #include<string.h>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<map>
 7 #include<set>
 8 #include<queue>
 9 #include<stack>
10 #define FOR(i,n) for(i=0;i<(n);i++)
11 #define CLR(a) memset(a,0,sizeof(a))
12 #define CIN(a) scanf("%d",&a)
13 typedef long long ll;
14 using namespace std;
15 ll a[1000005]; //a[i]=x^(i*1e12)=x^((i-1)*1e12)*x^1e12=a[i-1]*a[1]
16                //a[1]=b[1e6]
17 ll b[1000005]; //b[i]=x^(i*1e6) =x^((i-1)*1e6) *x^1e6 =b[i-1]*b[1]
18                //b[1]=c[1e6]
19 ll c[1000005]; //c[i]=x^i=c[i-1]*c[1]
20                //c[1]=x;
21 //x^y=a[y/1e12]*b[y%1e12/1e6]*c[y%1e6];
22 ll e12=1000000000000LL;
23 ll e6=1000000LL;
24 ll nextrandom(ll y,ll MOD)
25 //随机数生成器,不用改
26 //之所以要随机数生成器,是因为后台没办法上传太大的文件
27 //产生的随机数是为了测试代码效率,所有产生的随机数在[1,10^18]内
28 {
29     y=y*y*MOD;
30     if(y&1LL<<63) y=~y+1;
31     return y%1000000000000000000LL+1;
32 }
33 ll init(ll a[],ll x,ll MOD)
34 {
35     a[0]=1;
36     a[1]=x;
37     for(int i=2;i<=e6;i++)
38     {
39         a[i]=(a[i-1]*x)%MOD;
40     }
41     return a[e6];
42 }
43 ll f3(ll x,ll y,ll MOD)
44 {
45     return (a[y/e12]*b[y%e12/e6])%MOD*c[y%e6]%MOD;
46 }
47 int main()
48 {
49     ll x,q,y,MOD=1000000007LL,z,ans;
50     while(scanf("%lld",&x)!=EOF)//x<=10^9
51     {
52         init(a,init(b,init(c,x,MOD),MOD),MOD);
53         scanf("%lld%lld",&q,&y);//q<=5000000,y<=10^18
54         ans=0;
55         while(q--)
56         {
57             ans=(ans+f3(x,y,MOD))%MOD;
58             y=nextrandom(y,MOD);
59         }
60         printf("%lld\n",ans);
61     }
62     return 0;
63 }
View Code

D.求众数

用map保存每个数出现的次数,用一个set保存出现次数最多的书,并保存当前出现次数最多的次数,每次添加一个数时取出这个数原本出现的次数,将它加一然后和和原本的最多的次数比较,如果相同则将这个数添加进set,如果超过了原本的次数则清空原本的set然后将这个数添加到set内,同时更新最多次数。查询时遍历一遍set输出。

 1 #include<stdio.h>
 2 #include<math.h>
 3 #include<string.h>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<map>
 7 #include<set>
 8 #include<queue>
 9 #include<stack>
10 #define FOR(i,n) for(i=0;i<(n);i++)
11 #define CLR(a) memset(a,0,sizeof(a))
12 #define CIN(a) scanf("%d",&a)
13 typedef long long ll;
14 using namespace std;
15 /*
16 操作1:插入一个数
17 操作2:计算众数
18 */
19 map<int,int> m;
20 set<int> s;
21 int ma;
22 void in(int x){
23     map<int,int>::iterator it=m.find(x);
24     if(it!=m.end()){
25         it->second++;
26         if(it->second > ma){
27             s.clear();
28             s.insert(x);
29             ma=it->second;
30         }else if(it->second==ma){
31             s.insert(x);
32         }
33     }else{
34         m[x]=1;
35         if(ma<=1) s.insert(x);
36     }
37 }
38 void get(){
39     set<int>::iterator it;
40     for(it=s.begin();it!=s.end();it++){
41         if(it!=s.begin()) printf(" ");
42         printf("%d",*it);
43     }
44     printf("\n");
45 }
46 int main(){
47     int n,x,z;
48     while(scanf("%d",&n)!=EOF){//n<=20w
49         ma=-1;
50         s.clear();
51         m.clear();
52         while(n--){
53             scanf("%d",&z);
54             if(z==1){//插入一个数
55                 scanf("%d",&x);//int范围内
56                 in(x);
57             }else if(z==2){//求众数
58                 get();
59             }
60         }
61     }
62     return 0;
63 }
View Code

E.求中位数

用一个大顶堆和一个小顶堆保存整个数组,维护大顶堆内的所有数小于等于小顶堆内的所有数。如果总数是偶数时,维护两个堆内的元素个数相等,否则大顶堆内数字的个数比小顶堆内多一。查询时,如果大顶堆和小顶堆内的元素个数相同,则分别取出两个堆顶元素相加除以2,否则取出大顶堆的堆顶元素。

 1 #include<stdio.h>
 2 #include<math.h>
 3 #include<string.h>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<map>
 7 #include<set>
 8 #include<queue>
 9 #include<stack>
10 #define FOR(i,n) for(i=0;i<(n);i++)
11 #define CLR(a) memset(a,0,sizeof(a))
12 #define CIN(a) scanf("%d",&a)
13 typedef long long ll;
14 using namespace std;
15 priority_queue<int> p1;
16 priority_queue<int,vector<int>,greater<int> >  p2;
17 void in(int x){
18     if(p1.size()==p2.size()){
19         p2.push(x);
20         p1.push(p2.top());
21         p2.pop();
22     }else{
23         p2.push(x);
24         if(p2.top()<p1.top())
25         {
26             p1.push(p2.top());
27             p2.pop();
28             p2.push(p1.top());
29             p1.pop();
30         }
31     }
32 }
33 void mid(){
34     if(p1.size()==p2.size()){
35         if(((ll)p1.top()+p2.top())%2==0) printf("%d\n",(int)(((ll)p1.top()+p2.top())/2));
36         else printf("%.1lf\n",(1.0*p1.top()+p2.top())/2);
37     }else printf("%d\n",p1.top());
38 }
39 int main(){
40     int n,z,x;
41     while(scanf("%d",&n)!=EOF){//n<=20w;
42         while(!p1.empty()) p1.pop();
43         while(!p2.empty()) p2.pop();
44         while(n--){
45             scanf("%d",&z);
46             if(z==1){//插入一个数
47                 scanf("%d",&x);//int范围内
48                 in(x);
49             }else if(z==2){//查询中位数
50                 mid();
51             }
52         }
53     }
54     return 0;
55 }
View Code

F.求平均数

两个树状数组维护集合的总和合数量。查询时取出区间值相除。要注意的是总和可能是负数,不要直接拿去求最大公约数。不然可能求出来的公约数是负数。

 1 #include<stdio.h>
 2 #include<math.h>
 3 #include<string.h>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<map>
 7 #include<set>
 8 #include<queue>
 9 #include<stack>
10 #define FOR(i,n) for(i=0;i<(n);i++)
11 #define CLR(a) memset(a,0,sizeof(a))
12 #define CIN(a) scanf("%d",&a)
13 typedef long long ll;
14 using namespace std;
15 #define MAXLEN 100005
16 int s[MAXLEN],num[MAXLEN],n;
17 int Lowbit(int x){return x&(-x);}
18 int GCD(int a,int b){return b?GCD(b,a%b):a;}
19 int sum(int c[],int end){
20     int sum=0;
21     while(end>0){
22         sum+=c[end];
23         end-=Lowbit(end);
24     }
25     return sum;
26 }
27 void update(int c[],int pos,int num){
28     while(pos<=n){
29         c[pos]+=num;
30         pos+=Lowbit(pos);
31     }
32 }
33 void print(int a,int b){
34     if(!b) {printf("Error!\n");return;}
35     int gcd=GCD(a,b);
36     printf("%d/%d\n",a/gcd,b/gcd);
37 }
38 int main(){
39     int z,q,a,b;
40     while(scanf("%d%d",&n,&q)!=EOF){
41         memset(s,0,sizeof(s));
42         memset(num,0,sizeof(num));
43         while(q--){
44             scanf("%d%d%d",&z,&a,&b);
45             if(z==1){
46                 update(s,a,b);
47                 update(num,a,1);
48             }else{
49                 int S=sum(s,b)-sum(s,a-1);
50                 int n=sum(num,b)-sum(num,a-1);
51                 if(S<0){
52                     printf("-");
53                     print(-S,n);
54                 }else print(S,n);
55             }
56         }
57     }
58     return 0;
59 }
View Code

G.割绳子问题

二分枚举绳子的长度,每次判断能否得到k个这样的长度的绳子。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <math.h>
 4 #include <algorithm>
 5 using namespace std;
 6 int N,K,num[10005];
 7 long long sum;
 8 int Judge(int Num)
 9 {
10     int Sign=0,i;
11     for(i=0;i<N;i++)
12     {
13         Sign+=(num[i]/Num);
14     }
15     if(Sign>=K) return 1;
16     return 0;
17 }
18 int main()
19 {
20     int i;
21    // freopen("0.in","r",stdin);
22    // freopen("0.out","w",stdout);
23     while(scanf("%d%d",&N,&K)!=EOF)
24     {
25         sum=0;
26         for(i=0;i<N;i++)
27         {
28             scanf("%d",&num[i]);
29             sum+=num[i];
30         }
31         sum/=K;
32         int L=0,R=sum,Mid;
33         while((R-L)>=1)
34         {
35             if(R-1==L)
36             {
37                 if(Judge(R)) {L=R;break;}
38                 else if(Judge(L)){L=L;break;}
39             }
40             else
41             {
42                 Mid = (L+R)/2;
43                 if(Judge(Mid)) L=Mid;
44                 else R=Mid;
45             }
46  
47         }
48       //  printf("%.2f=>%d\n",L,(int)(L+EXP));
49          printf("%d\n",L);
50     }
51     return 0;
52 }
View Code

 

posted on 2015-05-17 23:02  T^T  阅读(519)  评论(0编辑  收藏  举报

导航