2017-10-07清北模拟赛

 

1 //电脑蓝屏,三个题60分暴力全部丢失。。
事故。

 

noip提高组模拟赛

 

1.计数

(count.cpp/c/pas)

时间限制:1s

内存限制:256MB

【问题描述】

    给出m个数a[1],a[2],…,a[m]

    求1~n中有多少数不是a[1],a[2],…,a[m]的倍数。

【输入】

输入文件名为count.in。

第一行,包含两个整数:n,m

第二行,包含m个数,表示a[1],a[2],…,a[m]

【输出】

输出文件名为count.out。

输出一行,包含1个整数,表示答案

【输入输出样例】

count.in

count.out

10 2

2 3

3

【数据说明】

对于60%的数据,1<=n<=106

对于另外20%的数据,m=2

对于100%的数据,1<=n<=109,0<=m<=20,1<=a[i]<=109

 

 1 /*
 2 暴力做法:m*n    枚举ai,数组记录每个在n内的ai的倍数是否出现过,统计ans 
 3 正解:容斥原理,对于选取的ai的个数,奇数ans减去贡献,偶数加上贡献,累乗ai注意取gcd 
 4 */
 5 #include <algorithm>
 6 #include <cstdio>
 7 
 8 #define LL long long
 9 inline void read(LL &x)
10 {
11     x=0; register char ch=getchar();
12     for(; ch>'9'||ch<'0'; ) ch=getchar();
13     for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
14 }
15 #define GCD(a,b) (std::__gcd(a,b))
16 const int N(26);
17 LL n,m,a[N],ans;
18 
19 void DFS(int op,int cnt,LL sum)
20 {
21     if(sum>n) return ;
22     if(cnt==m+1) { ans+=n/sum*op; return ; }
23     DFS(op,cnt+1,sum);
24     DFS(-op,cnt+1,sum/GCD(sum,a[cnt])*a[cnt]);
25 }
26 
27 int Presist()
28 {
29     read(n);    read(m);
30     for(int i=1; i<=m; ++i) read(a[i]);
31     DFS(1,1,1);    printf("%lld\n",ans);
32     return 0;
33 }
34 
35 int Aptal=Presist();
36 int main(int argc,char**argv){;} 
AC

 

 

 

 

2.第k大区间

(kth.cpp/c/pas)

时间限制:1s

内存限制:256MB

【问题描述】

定义一个长度为奇数的区间的值为其所包含的的元素的中位数。

现给出n个数,求将所有长度为奇数的区间的值排序后,第K大的值为多少。

【输入】

输入文件名为kth.in。

       第一行两个数n和k

第二行,n个数。(0<=每个数<231

【输出】

输出文件名为kth.out。

一个数表示答案。

【输入输出样例】

kth.in

kth.out

4 3

3 1 2 4

2

 

【样例解释】

[l,r]表示区间l~r的值

[1,1]:3

[2,2]:1

[3,3]:2

[4,4]:4

[1,3]:2

[2,4]:2

【数据说明】

对于30%的数据,1<=n<=100;

对于60%的数据,1<=n<=300

对于80%的数据,1<=n<=1000

对于100%的数据,1<=n<=100000, k<=奇数区间的数

 

 1 /*
 2 二分答案t,统计中位数大于等于t的区间有多少个。
 3 设a[i]为前i个数中有a[i]个数>=t,
 4 若奇数区间[l,r]的中位数>=t,则(a[r]-a[l-1])*2>r-l+1,即(a[r]*2-r)>(a[l-1]*2-l+1)。
 5 设b[i]=a[i]*2-i,统计每个b[i]有多少个b[j]<b[i] (j<i 且 j和i奇偶性不同)
 6 总复杂度O(nlognlogn)
 7 */
 8 #include <algorithm>
 9 #include <cstring>
10 #include <cstdio>
11 
12 #define max(a,b) (a>b?a:b)
13 
14 inline void read(int &x)
15 {
16     x=0; register char ch=getchar();
17     for(; ch>'9'||ch<'0'; ) ch=getchar();
18     for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
19 }
20 
21 const int N(100005);
22 
23 int n,k,a[N],num[N];
24 
25 
26 int l,r,mid,ans;
27 int tot[2][N<<1];
28 
29 #define lowbit(x) (x&((~x)+1))
30 inline void Update(int op,int x)
31 {
32     for(; x<=n<<1; x+=lowbit(x)) tot[op][x]++; 
33 }
34 inline int Query(int op,int x)
35 {
36     int ret=0;
37     for(; x; x-=lowbit(x)) ret+=tot[op][x];
38     return ret;
39 }
40 
41 inline bool check(int x)
42 {
43     int ret=0,sum=0,cnt=0;
44     memset(tot,0,sizeof(tot));
45     Update(0,n);
46     for(int i=1; i<=n; ++i)
47     {
48         sum+=(a[i]>=x);
49         cnt=sum<<1,cnt+=n-i;
50         ret+=Query(i&1,cnt);
51         Update(i+1&1,cnt);
52     }
53     return ret>k;
54 }
55 
56 int Presist()
57 {
58     read(n),read(k);
59     for(int i=1; i<=n; ++i)
60         read(a[i]),num[i]=a[i];
61     std::sort(num+1,num+n+1);
62     for(int i=1; i<=n; ++i)
63       if(num[i]!=num[i-1])
64          num[++num[0]]=num[i];
65     for(l=0,r=num[0]+1; l<=r; )
66     {
67         mid=l+r>>1;
68         if(check(num[mid]))
69         {
70             ans=mid;
71             l=mid+1;
72         }
73         else r=mid-1;
74     }
75     printf("%d\n",num[ans]);
76     return 0;
77 }
78 
79 int Aptal=Presist();
80 int main(int argc,char**argv){;} 
AC

 

 

 

 

 

 

3. 区间求和

(sum.cpp/c/pas)

时间限制:2s

内存限制:256MB

【问题述】

    有n个数,给定一个k,求所有长度大于等于k的区间中前k大数的总和。这样就比较简单相信大家都会,所以此题要求当k=1~n的总和,即求

 

【输入】

输入文件名为sum.in。

输入五个数n,a1,A,B,C。a1表示第一个数,A,B,C用来生成其余n-1个数。a(i)=(a(i-1)*A+B)mod C。1<=n<=1,000,000,0<=a1,A,B,C<=1,000,000,000

【输出】

输出文件名为sum.out。

一个数表示答案,最后答案对1,000,000,007取模。

 

【输入输出样例】

sum.in

sum.out

3 3 1 1 10

63

 

样例解释】

三个数为3,4,5

K=1:[1,1]=3,[1,2]=[2,2]=4,[1,3]=[2,3]=[3,3]=5

(表示各个区间在k=1时的答案)

K=2:[1,2]=7,[2,3]=[1,3]=9

K=3:[1,3]=12

【数据说明】

对于30%的数据,1<=n<=100

对于60%的数据,1<=n<=300

对于80%的数据,1<=n<=1000

对于100%的数据,1<=n<=1000000

 

模拟瞎暴力60分做法,枚举左右端点,得到k个最大数的和

设区间[l,r]的贡献为sum,只考虑K取不同值时整个区间的贡献,

新加一个a[r+1],设[l,r]中小于a[r+1]的数有x个,大于a[r+1]的数的和为y

a[r+1]使[l,r+1]多了a[r+1]*(x+1),因为统计不比他大的数会统计(x+1)次

这样子推一下

 

(因为比自己小的数与自己在同一区间内会增加自己被加的次数,所以统计所有比自己小的数有多少次在同一区间)对于上式的第一部分可以统计每个数前面比他小的数所在的位置总和,然后*a[j]*(n−j+1)即可,这可以按权值从小到大考虑每个数,然后用树状数组维护。第二部分类似,第三部分枚举一遍即可。

 

 1 #include <algorithm>
 2 #include <cstdio>
 3 
 4 inline void read(int &x)
 5 {
 6     x=0; register char ch=getchar();
 7     for(; ch>'9'||ch<'0'; ) ch=getchar();
 8     for(; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
 9 }
10 
11 const int mod(1e9+7);
12 const int N(1100000);
13 std::pair<int,int>a[N];
14 
15 int n,A,B,C,ans;
16 
17 int sum[N][2];
18 #define lowbit(x) (x&((~x)+1))
19 inline void Update(int i,int x,int op)
20 {
21     sum[0][op]+=x,sum[0][op]-=sum[0][op]>=mod?mod:0;
22     for(; i<=n; i+=lowbit(i))
23         sum[i][op]+=x,sum[i][op]-=sum[i][op]>=mod?mod:0;
24 }
25 inline int Query(int i,int op)
26 {
27     int ret=0;
28     for(; i; i-=lowbit(i))
29         ret+=sum[i][op],ret-=ret>=mod?mod:0;
30     return ret;
31 }
32 
33 int Presist()
34 {
35     read(n),read(a[1].first),read(A),read(B),read(C);
36     a[1].second=1;
37     for(int i=2; i<=n; ++i)
38     {
39         a[i].second=i;
40         a[i].first=(1ll*a[i-1].first*A+1ll*B)%C;
41     }
42     std::sort(a+1,a+n+1);
43     for(register int t1,t2,t3,i=1; i<=n; ++i)
44     {
45         t1=Query(a[i].second,0);
46         t2=sum[0][1]-Query(a[i].second-1,1);
47         t2+=mod; if(t2<0) t2+=mod;
48         t3=(1ll*t1*(n-a[i].second+1)+1ll*a[i].second*t2)%mod;
49         t3=(t3+1ll*a[i].second*(n-a[i].second+1))%mod;
50         ans=(ans+1ll*a[i].first*t3)%mod;
51         Update(a[i].second,a[i].second,0);
52         Update(a[i].second,n-a[i].second+1,1);
53     }
54     printf("%d",ans);
55     return 0;
56 }
57 
58 int Aptal=Presist();
59 int main(int argc,char**argv){;}
AC

 

posted @ 2017-10-12 09:18  Aptal丶  阅读(273)  评论(0编辑  收藏  举报