本学校高一同学又迎来了一次考试。
本蒟蒻身为验题人,自然要写一个题解来帮助大家(骗访问量)啦。
T1:
显然满足条件的数mod m相同,这样我们开m个vector把mod m相同的数放进同一个vector里。能否有解判断size即可。
答案要求字典序最小,我们比较这些vector的第一个元素(最小的),显然它们两两不可能相同,所以判断它们的大小即可比较字典序。
(话说这题后70分数据是我造的,前面30分队长说有两个"No",某人排序反了只有20,说明我还把他WA了,嗯,没出锅)
代码:
1 #include<bits/stdc++.h>
2 const int maxe=1e6+1e2;
3
4 std::vector<int> v[maxe];
5
6 int main() {
7 static int n,m,k,t,sel=-1;
8 scanf("%d%d%d",&n,&k,&m) , assert(m&&m<=1e6);
9 while(n--) scanf("%d",&t) , v[t%m].push_back(t);
10 for(int i=0;i<m;i++) {
11 if( v[i].size() ) std::sort(v[i].begin(),v[i].end() );
12 if( (signed) v[i].size() >= k && ( !~sel || *v[sel].begin() > *v[i].begin() ) ) sel = i;
13 }
14 if( !~sel ) return puts("No"),0;
15 puts("Yes");
16 for(int i=0;i<k;i++) printf("%d%c",v[sel][i],i!=k-1?' ':'\n');
17 return 0;
18 }
T2:
这不是裸的三维偏序吗?
一开始队长说256mb内存于是我花了10分钟写了一发树套树。
然后队长说32mb内存于是我又花了10分钟写了一发cdq。
然后队长说数据范围卡cdq,我......
这个三维偏序很特殊,全都是一个排列,我们考虑能否找到什么特殊性质。
一个二元组在三个排列中出现,要么三个顺序,要么有且只有一个顺序(你说两个顺序?我们把这两个元素交换一下就成一个顺序了)。于是我们考虑补集转化,求出非顺序的对数,用C(n,2)去减就是答案。
怎么计算?我们把排列转置一下(a[in[i]]=i),然后两两一组求逆序对。显然一对非顺序的(i,j)会被算且仅算两遍。然后就能得出答案了。
(队长朝我要正好卡掉cdq的数据范围,我说开O2跑1s正解可过1e6,然后他把数据范围设置为2e6开了2s,于是我过了标程TLE了......)
实际上这题复杂度全在IO,于是fread快读大法好。
树套树代码:
1 #include<bits/stdc++.h>
2 typedef long long int lli;
3 const int maxn=1e5+1e2,maxe=1e7+1e2;
4
5 int n;
6 lli ans;
7
8 struct SegmentTree {
9 int lson[maxe],rson[maxe],sum[maxe],cnt;
10 inline void insert(int &pos,int l,int r,const int &tar) {
11 if( !pos ) pos = ++cnt;
12 ++sum[pos];
13 if( l == r ) return;
14 const int mid = ( l + r ) >> 1;
15 tar <= mid ? insert(lson[pos],l,mid,tar) : insert(rson[pos],mid+1,r,tar);
16 }
17 inline int query(int pos,int l,int r,const int &ll,const int &rr) {
18 if( !pos || ( ll <= l && r <= rr ) ) return sum[pos];
19 const int mid = ( l + r ) >> 1;
20 if( rr <= mid ) return query(lson[pos],l,mid,ll,rr);
21 else if( ll > mid ) return query(rson[pos],mid+1,r,ll,rr);
22 else return query(lson[pos],l,mid,ll,rr) + query(rson[pos],mid+1,r,ll,rr);
23 }
24 }sgt;
25
26 struct BinaryIndexTree {
27 int rt[maxn];
28 #define lowbit(x) (x&-x)
29 inline void update(int x,int y) {
30 while( x <= n ) sgt.insert(rt[x],1,n,y) , x += lowbit(x);
31 }
32 inline int query(int x,int y) {
33 int ret = 0; --x , --y;
34 while( x ) ret += sgt.query(rt[x],1,n,1,y) , x -= lowbit(x);
35 return ret;
36 }
37 }bit;
38
39 struct Point {
40 int z,x,y;
41 friend bool operator < (const Point &a,const Point &b) {
42 return a.z < b.z;
43 }
44 }ps[maxn];
45
46 int main() {
47 scanf("%d",&n);
48 for(int i=1,t;i<=n;i++) scanf("%d",&t) , ps[t].z = i;
49 for(int i=1,t;i<=n;i++) scanf("%d",&t) , ps[t].x = i;
50 for(int i=1,t;i<=n;i++) scanf("%d",&t) , ps[t].y = i;
51 std::sort(ps+1,ps+1+n);
52 for(int i=1;i<=n;i++) ans += bit.query(ps[i].x,ps[i].y) , bit.update(ps[i].x,ps[i].y);
53 return printf("%lld\n",ans) , 0;
54 }
CDQ代码:
1 #include<bits/stdc++.h>
2 typedef long long int lli;
3 const int maxn=1e6+1e2,maxe=1e7+1e2;
4
5 int n;
6 lli ans;
7
8 struct BinaryIndexTree {
9 int dat[maxn];
10 #define lowbit(x) (x&-x)
11 inline void update(int x,int y) {
12 while( x <= n ) dat[x] += y , x += lowbit(x);
13 }
14 inline int query(int x) {
15 int ret = 0; --x;
16 while(x) ret += dat[x] , x -= lowbit(x);
17 return ret;
18 }
19 }bit;
20
21 int cmp = 0;
22 struct Point {
23 int z,x,y;
24 friend bool operator < (const Point &a,const Point &b) {
25 return !cmp ? a.z < b.z : ( a.x != b.x ? a.x < b.x : a.y < b.y );
26 }
27 }ps[maxn];
28
29 inline void solve(int l,int r) {
30 if( l == r ) return;
31 const int mid = ( l + r ) >> 1;
32 solve(l,mid) , solve(mid+1,r);
33 cmp = 1 , std::sort(ps+l,ps+mid+1) , std::sort(ps+mid+1,ps+r+1);
34 int cl = l , cr = mid + 1;
35 while( cl <= mid || cr <= r ) {
36 if( cl > mid ) ans += bit.query(ps[cr++].y);
37 else if( cr > r ) bit.update(ps[cl++].y,1);
38 else if( ps[cl].x <= ps[cr].x ) bit.update(ps[cl++].y,1);
39 else ans += bit.query(ps[cr++].y);
40 }
41 for(int i=l;i<=mid;i++) bit.update(ps[i].y,-1);
42 }
43
44 int main() {
45 scanf("%d",&n);
46 for(int i=1,t;i<=n;i++) scanf("%d",&t) , ps[t].z = i;
47 for(int i=1,t;i<=n;i++) scanf("%d",&t) , ps[t].x = i;
48 for(int i=1,t;i<=n;i++) scanf("%d",&t) , ps[t].y = i;
49 cmp = 0 , std::sort(ps+1,ps+1+n) , solve(1,n);
50 return printf("%lld\n",ans) , 0;
51 }
正解代码:
1 #pragma GCC optimize(2)
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 #include<cctype>
6 typedef long long int lli;
7 const int maxn=2e6+1e2;
8
9 int a[maxn],b[maxn],c[maxn],n;
10 lli ans;
11
12 struct BinaryIndexTree {
13 int dat[maxn];
14 #define lowbit(x) (x&-x)
15 inline void update(int x) {
16 while( x <= n ) ++dat[x] , x += lowbit(x);
17 }
18 inline int query(int x) {
19 int ret = 0;
20 while(x) ret += dat[x] , x -= lowbit(x);
21 return ret;
22 }
23 inline void reset() {
24 memset(dat,0,sizeof(dat));
25 }
26 }bit;
27
28 struct Point {
29 int x,y;
30 friend bool operator < (const Point &a,const Point &b) {
31 return a.x < b.x;
32 }
33 }ps[maxn];
34
35 inline lli C(lli n) {
36 return n * ( n - 1 ) / 2;
37 }
38
39 inline lli calc(int* a,int* b) {
40 lli ret = 0;
41 for(int i=1;i<=n;i++) ps[i] = (Point){a[i],b[i]};
42 bit.reset() , std::sort(ps+1,ps+1+n);
43 for(int i=1;i<=n;i++) bit.update(ps[i].y) , ret += i - bit.query(ps[i].y);
44 return ret;
45 }
46
47 inline char nextchar() {
48 static const int BS = 1 << 21;
49 static char buf[BS],*st=buf+BS,*ed=buf+BS;
50 if( st == ed ) ed = buf + fread(st=buf,1,BS,stdin);
51 return st == ed ? -1 : *st++;
52 }
53 inline int getint() {
54 int ret = 0;
55 char ch;
56 while( !isdigit(ch=nextchar()) );
57 do ret=ret*10+ch-'0'; while( isdigit(ch=nextchar()) );
58 return ret;
59 }
60
61 int main() {
62 n = getint();
63 for(int i=1;i<=n;i++) a[getint()] = i;
64 for(int i=1;i<=n;i++) b[getint()] = i;
65 for(int i=1;i<=n;i++) c[getint()] = i;
66 ans = calc(a,b) + calc(a,c) + calc(b,c);
67 ans = C(n) - ( ans >> 1 );
68 return printf("%lld\n",ans) , 0;
69 }
T3:
我能告诉你这题打表找规律可过?
我们考虑暴力找规律,发现二进制每一位被统计个数恰好为更低位(第0位为n/2)次数的一半,且上取整还是下取整与n-1在这位的值有关。于是我们就能AC了。
证明也很简单:
从边权低到高贪心。
考虑边权为2^0的边,差为1的点相互连接,这样的有n/2组,我们缩点。
考虑边权为2^1的边,差为2的点相互连接,这样的有n/2/2组,我们缩点。
以此类推即可。
代码:
1 #include<bits/stdc++.h>
2 typedef long long int lli;
3
4 lli n,cur,ans;
5
6 int main() {
7 scanf("%lld",&n) , --n , cur = n;
8 for(int i=0;n;n>>=1,i++) {
9 if( ( cur = ( cur + ( n & 1 ) ) >> 1 ) & 1 ) ans ^= 1ll << i;
10 }
11 return printf("%lld\n",ans) , 0;
12 }
来源:oschina
链接:https://my.oschina.net/u/4409548/blog/3986936