圈钱学堂7日游 - Day1 上午

 

此文为博主原创,转载...转载这种文章有意思吗qwq

严禁各OJ在未经博主同意的情况下擅自使用博文中的题面作为OJ题目。

因为博主在清北上课期间天天划水,回房间就颓,所以博客发表时间推后了一周(Day1原本是10.28...)

第一次写集训游记好激动啊www

Day1授课老师是北京大学张浩威(张过亿),上午的题水得不行...然后下午就...QAQ

话不多说,放题。

 

上午【二分专场】

 

立方数(cubic)

Time Limit:1000ms   Memory Limit:128MB

题目描述

有T次询问,每次给定一个数P,问这个数是不是立方数。

输入格式(cubic.in)

第一行一个数T,表示有T组数据。

接下来T行,每行一个数P。

输出格式(cubic.out)

输出T行,对于每个数如果是立方数,输出“YES”,否则输出“NO”。

数据范围

p<=10^18,T<=100。

 

分析:

由于立方满足单调性,二分一个数,判断这个数的立方是否等于给定的P。

AC代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 
 6 inline void read(int &x)
 7 {
 8     char ch = getchar(),c = ch;x = 0;
 9     while(ch < '0' || ch > '9') c = ch,ch = getchar();
10     while(ch <= '9' && ch >= '0') x = (x<<1)+(x<<3)+ch-'0',ch = getchar();
11     if(c == '-') x = -x;
12 }
13 
14 inline void read(long long &x)
15 {
16     char ch = getchar(),c = ch;x = 0;
17     while(ch < '0' || ch > '9') c = ch,ch = getchar();
18     while(ch <= '9' && ch >= '0') x = (x<<1)+(x<<3)+ch-'0',ch = getchar();
19     if(c == '-') x = -x;
20 }
21 
22 int t,flag;
23 long long l,r,mid,tmp,p;
24 
25 int main()
26 {
27     freopen("cubic.in","r",stdin);
28     freopen("cubic.out","w",stdout);
29     read(t);
30     while(t --)
31     {
32         read(p);
33         flag = false;
34         l = 0,r = 1000001;
35         while(l <= r)
36         {
37             mid = (l+r)>>1;
38             tmp = mid*mid*mid;
39 //            printf("%I64d %I64d\n",mid,tmp);
40             if(tmp == p) {
41                 flag = true;
42                 break;
43             }
44             else if(tmp < p) l = mid+1;
45             else if(tmp > p) r = mid-1;
46         }
47         if(flag) printf("YES\n");
48         else printf("NO\n");
49     }
50     return 0;
51 }

 

立方数2(cubicp)

Time Limit:1000ms   Memory Limit:128MB

题目描述

若一个数可以被写作是两个立方数的差,则这个数就是“立方差数”,例如7(8-1),26(27-1),19(27-8)都是立方差数。

有T次询问,每次给定一个数P,问这个数是不是立方差数。P是质数。

输入格式(cubicp.in)

第一行一个数T,表示有T组数据。

接下来T行,每行一个数P。

输出格式(cubicp.out)

输出T行,对于每个数如果是立方差数,输出“YES”,否则输出“NO”。

数据范围

p<=10^12,T<=100。

 

分析:

根据立方差公式x3-y3 = (x-y)(x2+xy+y2)可知,如果P是质数,则x-y=1y=x-1,代入化简得x3-y3 = 3x*(x-1)+1.

立方差依然满足单调性,二分x的值进行判断即可。

AC代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 
 6 inline void read(int &x)
 7 {
 8     char ch = getchar(),c = ch;x = 0;
 9     while(ch < '0' || ch > '9') c = ch,ch = getchar();
10     while(ch <= '9' && ch >= '0') x = (x<<1)+(x<<3)+ch-'0',ch = getchar();
11     if(c == '-') x = -x;
12 }
13 
14 inline void read(long long &x)
15 {
16     char ch = getchar(),c = ch;x = 0;
17     while(ch < '0' || ch > '9') c = ch,ch = getchar();
18     while(ch <= '9' && ch >= '0') x = (x<<1)+(x<<3)+ch-'0',ch = getchar();
19     if(c == '-') x = -x;
20 }
21 
22 int t,flag;
23 long long l,r,mid,tmp,p;
24 
25 int main()
26 {
27     freopen("cubicp.in","r",stdin);
28     freopen("cubicp.out","w",stdout);
29     read(t);
30     while(t --)
31     {
32         read(p);
33         flag = false;
34         l = 0,r = 1000001;
35         while(l <= r)
36         {
37             mid = (l+r)>>1;
38             tmp = 3*mid*(mid-1)+1;
39 //            printf("%I64d %I64d\n",mid,tmp);
40             if(tmp == p){
41                 flag = true;
42                 break;
43             }
44             else if(tmp < p) l = mid+1;
45             else if(tmp > p) r = mid-1;
46         }
47         if(flag) printf("YES\n");
48         else printf("NO\n");
49     }
50     return 0;
51 }

 

猜数字(number)

Time Limit:1000ms   Memory Limit:128MB

题目描述

有n个互不相同的正整数,每次猜一段区间的最小值。形如[li,ri]这段区间的数字的最小值一定等于xi。

我们总能构造出一种方案使得猜测正确。直到两个猜测产生矛盾。

例如猜[1,3]的最小值是2,[1,4]的最小值是3,这显然就是矛盾的。问第几次猜数字开始就已经矛盾了。

输入格式(number.in)

第一行两个数n和T,表示有n个数字,猜了T次。
接下来T行,每行三个数分别表示li,ri和xi。

输出格式(number.out)

输出一个数表示第几次开始出现矛盾,如果一直没出现矛盾输出T+1。

数据范围

1<=n,T<=1000000,1<=li<=ri<=n,1<=xi<=n(不保证一开始的所有数都是1~n的)。

 

分析:

出现矛盾的原因是[l,r]曾经被一个比当前x更大的值完全覆盖过。

显然我们要对这些区间排一个序。由矛盾原因可以想到,要按照xi的值排序。

由于【1~mid没有出现矛盾,则1~mid-1也不会出现矛盾。1~mid出现矛盾,1~mid+1也出现矛盾】,可二分。

二分过程中,用一个并查集维护已经覆盖过的区间。复杂度O(nlogn*α(n))。

这波操作太巧妙了www

这道题的标程每次二分都排序一次,是会TLE的。正确做法是先排序,然后在二分时找出mid范围内的区间。

//%%%rqy太强了!运行时间碾压标程!(最后一个测试点 标程:1322ms  我修改后的标程:736ms  RQY:348ms)

AC代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<queue>
 6 #include<stack>
 7 
 8 const int MAXN = 1000002;
 9 
10 int n,t,l,r,mid,lmin,lmax,rmin,rmax,ans,cnt;
11 int lf[MAXN],rt[MAXN],x[MAXN],fa[MAXN];
12 
13 struct QUES
14 {
15     int l,r,x,ord;
16 }q[MAXN];
17 
18 int cmp(QUES a,QUES b)
19 {return a.x > b.x;}
20 
21 inline int Min(int a,int b)
22 {return a<b?a:b;}
23 
24 inline int Max(int a,int b)
25 {return a>b?a:b;}
26 
27 inline int find(int x)
28 {return fa[x]==x?x:fa[x]=find(fa[x]);}
29 
30 bool check(int now)
31 {
32     register int i,j;cnt = 0;
33     for(i=1;i<=n+1;++i) fa[i]=i;
34     for(i = 1;i <= n;++ i)
35     {
36         if(q[i].ord > now) continue;
37         if(cnt == now) break; 
38         lf[++cnt] = q[i].l,rt[cnt] = q[i].r,x[cnt] = q[i].x;
39     }
40         
41     lmin = lmax = lf[1];
42     rmin = rmax = rt[1];
43     for(i = 2;i <= now;++ i)
44     {
45         if(x[i] < x[i-1])
46         {
47             if(find(lmax) > rmin) return true;
48             for(j = find(lmin);j <= rmax;++ j)
49                 fa[find(j)] = find(rmax+1);
50             lmin = lmax = lf[i];
51             rmin = rmax = rt[i];
52         }
53         else
54         {
55             lmin = Min(lmin,lf[i]);
56             lmax = Max(lmax,lf[i]);
57             rmin = Min(rmin,rt[i]);
58             rmax = Max(rmax,rt[i]);
59         }
60     }
61     if(find(lmax) > rmin) return true;
62     return false;
63 }
64 
65 int main()
66 {
67     scanf("%d%d",&n,&t);
68     for(int i = 1;i <= t;++ i)
69     {
70         scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].x);
71         q[i].ord = i;
72     }
73     ans = t+1;
74     l = 1,r = t;
75     std::sort(q+1,q+1+n,cmp);
76     while(l <= r)
77     {
78         mid = (l+r)>>1;
79         if(check(mid)) r = mid-1,ans = mid;
80         else l = mid+1;
81     }
82     printf("%d\n",ans);
83     return 0;
84 }

 

总结:

虽然我管上午叫二分专场,其实T1 T2在发现规律之后都是可以直接暴力枚举的。

然而我由于二分的时候右边界过大 溢出导致RE!!80分没有辣!!!

QAQ好气哦。

T3写了暴力和各种特判(然而并没有任何卵用)。出题人不能这样QAQ

期望:100+100=200  实际:60+60=120

posted @ 2017-11-05 14:21 超时空灰狼菌 阅读(...) 评论(...) 编辑 收藏