高一考试的题解
本学校高一同学又迎来了一次考试。
本蒟蒻身为验题人,自然要写一个题解来帮助大家(骗访问量)啦。
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 }