A. Divide it!
•题意
定义整数 n 上的三个操作:
如果可以经过上述操作使得 n 变为 1,输出最小操作次数,反之,输出-1;
•题解
易得 2 > 3/2 > 5/4;
操作执行的优先级 1 > 2 > 3;
按照优先级依次执行;
•AC代码
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 5 ll n; 6 int Solve() 7 { 8 int ans=0; 9 while(n%2 == 0) 10 { 11 n /= 2; 12 ans++; 13 } 14 while(n%3 == 0) 15 { 16 n /= 3; 17 ans += 2; 18 } 19 while(n%5 == 0) 20 { 21 n /= 5; 22 ans += 3; 23 } 24 return n == 1 ? ans:-1; 25 } 26 int main() 27 { 28 int test; 29 scanf("%d",&test); 30 while(test--) 31 { 32 scanf("%lld",&n); 33 printf("%d ",Solve()); 34 } 35 return 0; 36 }
B. Merge it!
•题意
给你一个包含 n 个数的序列 a;
定义序列 a 上的一个操作:合并任意两个元素;
你可以对序列 a 执行上述操作任意次,求操作后的序列最多有多少元素可以被 3 整除;
•题解
对于任意一个数 x ,如果 x 不是 3 的倍数,那么 x 最多加 2 就可以变成 3 的倍数;
首先求出 ai 最少加多少可以变成 3 的倍数;
共有三种可能:
①如果 ai%3 = 0,加0;
②ai%3 = 1,加2;
③ai%3 = 2,加1;
②和③结合正好是3的倍数,优先让②和③结合,剩余的自己结合;
•AC代码
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define INF 0x3f3f3f3f 5 #define mem(a,b) memset(a,b,sizeof(a)) 6 #define memF(a,b,n) for(int i=0;i<=n;a[i++]=b); 7 const int maxn=1e2+50; 8 9 int n; 10 int a[maxn]; 11 int b[3]; 12 13 int Solve() 14 { 15 b[0]=b[1]=b[2]=0; 16 for(int i=1;i <= n;++i) 17 { 18 int k=a[i]%3; 19 if(k == 0) 20 b[0]++; 21 else if(k == 1) 22 b[2]++; 23 else 24 b[1]++; 25 } 26 27 return b[0]+min(b[1],b[2])+abs(b[2]-b[1])/3; 28 } 29 int main() 30 { 31 // freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin); 32 int test; 33 scanf("%d",&test); 34 while(test--) 35 { 36 scanf("%d",&n); 37 for(int i=1;i <= n;++i) 38 scanf("%d",a+i); 39 printf("%d ",Solve()); 40 } 41 return 0; 42 }
C. Lose it!
•题意
给你一个包含 n 个整数的序列 a;
在删去 x 个数后,使得序列 a 可以划分成 (n-x) / 6 个 "good" 序列;
求 x 的最小值;
•题解
求出序列 a 最多有多少个 "good" 序列(假设有 ans 个),那么答案就是 n-6×ans;
•AC代码
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define INF 0x3f3f3f3f 5 #define mem(a,b) memset(a,b,sizeof(a)) 6 #define memF(a,b,n) for(int i=0;i<=n;a[i++]=b); 7 const int maxn=5e5+50; 8 9 int n; 10 int a[7]={0,4,8,15,16,23,42}; 11 map<int ,int >mymap; 12 13 int b[7];///b[1]:4来到v[4][b[1]]位置,b[2,...,6]同理 14 vector<int >v[7];///v[1]:存放4出现的所有位置,v[2,...,6]同理 15 int ans;///"good"序列个数 16 17 void DFS(int cur,int pre) 18 { 19 if(cur == 7) 20 { 21 ans++; 22 return ; 23 } 24 25 ///找到上一个位置pre之后的最左的位置 26 for(;b[cur] < v[cur].size() && v[cur][b[cur]] < pre;b[cur]++); 27 if(b[cur] == v[cur].size()) 28 return ; 29 ///查找下一个数的位置 30 DFS(cur+1,v[cur][b[cur]++]); 31 } 32 int Solve() 33 { 34 ans=0; 35 for(int i=0;i < v[1].size();++i) 36 DFS(2,v[1][i]);///枚举4的每个位置 37 38 return n-6*ans; 39 } 40 int main() 41 { 42 // freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin); 43 for(int i=1;i <= 6;++i) 44 mymap[a[i]]=i; 45 46 scanf("%d",&n); 47 for(int i=1;i <= n;++i) 48 { 49 int x; 50 scanf("%d",&x); 51 v[mymap[x]].push_back(i); 52 } 53 printf("%d ",Solve()); 54 return 0; 55 }
•非DFS
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define memF(a,b,n) for(int i=0;i <= n;a[i++]=b); 4 const int maxn=5e5+50; 5 6 int n; 7 int a[maxn]; 8 int num[10]={4,8,15,16,23,42}; 9 int b[50]; 10 vector<int >p[50]; 11 12 int Solve() 13 { 14 memF(b,0,49); 15 16 int ans=0;///最多构成ans个"good"序列 17 for(int i=0;i < p[4].size();++i) 18 { 19 int cur=p[4][i]; 20 for(int j=1;j <= 5;++j) 21 { 22 int index=num[j]; 23 for(;b[index] < p[index].size() && p[index][b[index]] <= cur;b[index]++); 24 25 if(b[index] == p[index].size()) 26 return n-6*ans; 27 28 ///p[index]的b[index]位置已使用,所以b[index]++ 29 cur=p[index][b[index]++]; 30 } 31 ans++; 32 } 33 return n-6*ans; 34 } 35 int main() 36 { 37 scanf("%d",&n); 38 for(int i=1;i <= n;++i) 39 { 40 scanf("%d",a+i); 41 p[a[i]].push_back(i); 42 } 43 printf("%d ",Solve()); 44 45 return 0; 46 }
•二分
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define memF(a,b,n) for(int i=0;i <= n;a[i++]=b); 4 const int maxn=5e5+50; 5 6 int n; 7 int a[maxn]; 8 int num[10]={4,8,15,16,23,42}; 9 vector<int >p[50]; 10 11 int Solve() 12 { 13 int ans=0;///最多构成ans个"good"序列 14 for(int i=0;i < p[4].size();++i) 15 { 16 int cur=p[4][i]; 17 for(int j=1;j <= 5;++j) 18 { 19 int index=num[j]; 20 ///二分查找p[index]中 > cur 的位置 21 vector<int >::iterator it=upper_bound(p[index].begin(),p[index].end(),cur); 22 if(it == p[index].end()) 23 return n-6*ans; 24 25 cur=*it; 26 p[index].erase(it);///it位置已被使用,删掉 27 } 28 ans++; 29 } 30 return n-6*ans; 31 } 32 int main() 33 { 34 scanf("%d",&n); 35 for(int i=1;i <= n;++i) 36 { 37 scanf("%d",a+i); 38 p[a[i]].push_back(i); 39 } 40 printf("%d ",Solve()); 41 42 return 0; 43 }
•效率比拼
二分效率:
非二分效率:
总结:
codeforces评测鸡是真的快呀;
D. Recover it!
•题意
构造包含 n 个数的数组 a,使得 a 经过下述操作,多出 n 个数;
这 2n 个数构成数组 b,即输入的 2n 个数;
输出 a 数组中的 n 个数;
•题解
这 2n 个数要平分到两个集合 U,V 中;
满足集合 U 通过上述两个操作可以推导出集合 V,并且是一一对应关系;
那么,考虑一下这 2n 个数中的最大值 x 要归到哪个集合?
①x 为素数,x∈V;
②x 为合数,x∈U;
根据这两个限定,首先将 b 排序,每次抽出最大值 x,判断 x 是否为素数;
①如果 x 为第 y 个素数,因为保证答案一定存在,那么 y 一定存在,并且 y 也是素数;
将 x 归到集合 V,y 归到集合 U;
②如果 x 为合数,那么 x 归到集合 U,x的小于x的最大的约数 y 也一定存在,将 y 归到集合 V;
最后输出集合 U 中的元素即可;
•Code
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mem(a,b) memset(a,b,sizeof(a)) 4 const int maxn=2e5+50; 5 6 int n; 7 int b[maxn<<1]; 8 map<int ,int >f; 9 int cnt; 10 int prime[maxn]; 11 bool isPrime[2750131+10]; 12 void Prime() 13 { 14 mem(isPrime,true); 15 cnt=1; 16 for(int i=2;cnt < (int)2e5;i++) 17 { 18 if(isPrime[i]) 19 prime[cnt++]=i; 20 for(int j=1;j < cnt && prime[j]*i <= 2750131;++j) 21 { 22 isPrime[prime[j]*i]=false; 23 if(i%prime[j] == 0) 24 break; 25 } 26 } 27 } 28 29 void Solve() 30 { 31 sort(b+1,b+2*n+1); 32 for(int i=2*n;i >= 1;--i) 33 { 34 int x=b[i]; 35 if(f[x] == 0) 36 continue; 37 38 int y=lower_bound(prime+1,prime+cnt,x)-prime; 39 if(y < cnt && prime[y] == x) 40 { 41 printf("%d ",y); 42 f[x]--; 43 f[y]--; 44 } 45 else 46 { 47 for(int i=2;;i++) 48 if(x%i == 0) 49 { 50 y=x/i; 51 break; 52 } 53 printf("%d ",x); 54 f[x]--; 55 f[y]--; 56 } 57 } 58 printf(" "); 59 } 60 int main() 61 { 62 Prime(); 63 64 scanf("%d",&n); 65 f.clear(); 66 for(int i=1;i <= 2*n;++i) 67 { 68 scanf("%d",b+i); 69 f[b[i]]++; 70 } 71 Solve(); 72 73 return 0; 74 }
E. Cover it!
•题意
从含有 n 个点,m 条边的无向图中取出 x 个点,这 x 个点需满足:
① x ≤ n/2;
②剩余的点至少与这 x 个点中的一个点有连边;
输出满足条件的这 x 个点;
•题解
二部图裸题;
找出集合 U 和集合 V,输出 |U| 和 |V| 中元素个数最少的集合;
•AC代码
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define INF 0x3f3f3f3f 5 #define mem(a,b) memset(a,b,sizeof(a)) 6 #define memF(a,b,n) for(int i=0;i<=n;a[i++]=b); 7 const int maxn=2e5+50; 8 9 int t; 10 int n,m; 11 int num; 12 int head[maxn]; 13 struct Edge 14 { 15 int to,next; 16 }G[maxn<<1]; 17 void addEdge(int u,int v) 18 { 19 G[num]=Edge{v,head[u]}; 20 head[u]=num++; 21 } 22 int col[maxn];///col[i]:节点i所属的集合 23 24 ///集合U中的元素染成0 25 ///集合V中的元素染成1 26 void DFS(int u,int k) 27 { 28 col[u]=k; 29 // printf("u=%d,k=%d ",u,k); 30 for(int i=head[u];~i;i=G[i].next) 31 { 32 int v=G[i].to; 33 if(col[v] != -1) 34 continue; 35 DFS(v,k^1); 36 } 37 } 38 void Solve() 39 { 40 memF(col,-1,n); 41 DFS(1,0); 42 int a=0,b=0; 43 for(int i=1;i <= n;++i) 44 if(col[i]) 45 a++; 46 else 47 b++; 48 49 int ans=a > b ? 0:1; 50 printf("%d ",min(a,b)); 51 for(int i=1;i <= n;++i) 52 if(col[i] == ans) 53 printf("%d ",i); 54 printf(" "); 55 } 56 void Init() 57 { 58 num=0; 59 memF(head,-1,n); 60 } 61 int main() 62 { 63 // freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin); 64 int test; 65 scanf("%d",&test); 66 while(test--) 67 { 68 scanf("%d%d",&n,&m); 69 Init(); 70 for(int i=1;i <= m;++i) 71 { 72 int u,v; 73 scanf("%d%d",&u,&v); 74 addEdge(u,v); 75 addEdge(v,u); 76 } 77 Solve(); 78 } 79 return 0; 80 }