Codeforces Round #580 (Div. 2)

桃扇骨 2023-08-17 16:26 164阅读 0赞

A题—-水题:

  1. int a[105],b[105];
  2. int main()
  3. {
  4. int n1,n2;
  5. cin>>n1;
  6. for(int i=0;i<n1;i++)
  7. cin>>a[i];
  8. sort(a,a+n1);
  9. cin>>n2;
  10. for(int i=0;i<n2;i++)
  11. cin>>b[i];
  12. sort(b,b+n2);
  13. cout<<a[n1-1]<<" "<<b[n2-1]<<endl;
  14. }

B题—-模拟题

题意:给定n个数字(数字范围为−10^9≤ai≤10^9),每个数字可以进行原基础上的加一或减一操作,问多少次操作之后这些数字的乘积为1?

思路:

要数字乘积为1 那么这些数字必须为-1与1

所以我们需要做的是让这些数字都靠近1与-1,另外处理数字0—-使他看情况变为1或-1

-3 -5 -5 -1 0 0 0 1 2

注明:这里需要处理一些细节

  1. int main()
  2. {
  3. int n,t;
  4. cin>>n;
  5. int a=0,b=0,c=0;
  6. long long ans=0;
  7. for(int i=0;i<n;i++)
  8. {
  9. cin>>t;
  10. if(t==0)
  11. c++;
  12. else if(t>0)
  13. {
  14. a++;
  15. ans+=(t-1);
  16. }
  17. else
  18. {
  19. b++;
  20. ans+=(-1-t);
  21. }
  22. }
  23. if(c==0)
  24. {
  25. if(a==0&&b)
  26. {
  27. if(b%2==1)
  28. ans+=2;
  29. }
  30. if(a&&b)
  31. {
  32. if(b%2==1)
  33. ans+=2;
  34. }
  35. }
  36. else
  37. {
  38. ans+=c;
  39. }
  40. cout<<ans<<endl;
  41. }

C题:规律模拟题

题意:给定数字n,让你求一个环,环上有2n个数字(1,2…2n),环上形成连续的n个数字其和与其他的环上形成连续的n个数字的和相差不大于1,问是否存在这样的环,存在输出该环

思路:我们可以得出a[i]-a[i+n]=1(或者-1) 即a[i]与a[i+n]相差1

我们只需求出n对这样的数 每对数两数之间相差1 其实就是1,2 ;3,4;5,6;然后我们注意到每次都是先相差正1,然后下一组相差负1

  1. int a[200005];
  2. int main()
  3. {
  4. int n;
  5. cin>>n;
  6. n=2*n;
  7. int sum=n*(n+1)/2;
  8. int x=(sum+1)/2;
  9. a[1]=1,a[n]=n;
  10. if((n/2)%2==0)
  11. cout<<"NO"<<endl;
  12. else{
  13. int t=1;
  14. for(int i=1;i<=n/2;i++)
  15. {
  16. t=2*i;
  17. if(i%2)
  18. {
  19. a[i]=t-1,a[n/2+i]=t;
  20. }
  21. else
  22. {
  23. a[i]=t,a[n/2+i]=t-1;
  24. }
  25. }
  26. cout<<"YES"<<endl;
  27. for(int i=1;i<=n;i++)
  28. {
  29. if(i!=n)
  30. cout<<a[i]<<" ";
  31. else
  32. cout<<a[i]<<endl;
  33. }
  34. }
  35. }

d题

思路:题目可以转化为求图中的最小环,从一个点去找路径,然后结束条件就是路径点又回到了起点,这就是环。然后记录最小的环的边数目。

枚举每个点的最小环

给你n个点,每个点都有权值,两个点当且仅当(ai&aj)!=0时才会有边.
让你求最小的循环长度 (循环中的点要大于等于3)

点的权值的上限是1e18,比2^60小.
易得结论:n>120时必定存在一个循环长度为3的环
假设前60个点每个点都不会与其他点连边,这是最坏的情况,也就是每个点都是2的k次方这样子
那么后面不论加什么点都会与前面60个点的其中至少一个点连有边,再考虑最坏的情况,加入120
个点后恰好每两个点有边,此时再加入任意一个点,即存在一个环.
注意点的权值可以为0,把权值为0的点剔除就好.
对于n<=120 跑个floyd最小环

ContractedBlock.gif ExpandedBlockStart.gif

  1. 1 #include <bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 #define ll long long
  4. 4 #define maxn 100010
  5. 5 const int inf = 0x3f3f3f3f;
  6. 6 ll a[maxn];
  7. 7 int path[500][500];
  8. 8 ll cost;
  9. 9 int vis[500],m;
  10. 10
  11. 11 void dfs(int u,int cnt,int x)//当前点 边数 遍历点的起点
  12. 12 {
  13. 13 vis[u]=1;
  14. 14 if(cnt>cost) //剪枝
  15. 15 return;
  16. 16 if(cnt>=3&&path[u][x])
  17. 17 {
  18. 18 cost=cnt;
  19. 19 return;
  20. 20 }
  21. 21
  22. 22 for(int v=1;v<=m;v++)
  23. 23 {
  24. 24 if(vis[v]==0&&path[u][v]&&v!=x)
  25. 25 {
  26. 26 // vis[i]=1;
  27. 27 dfs(v,cnt+1,x);
  28. 28 vis[v]=0;
  29. 29 }
  30. 30 }
  31. 31
  32. 32 }
  33. 33
  34. 34 int main()
  35. 35 {
  36. 36 int n;
  37. 37 scanf("%d",&n);
  38. 38 ll a[maxn],kk;
  39. 39 m=0;
  40. 40 for(int i=1;i<=n;i++)
  41. 41 {
  42. 42 scanf("%lld",&kk);
  43. 43 if(kk!=0)
  44. 44 {
  45. 45 m++;
  46. 46 a[m]=kk;
  47. 47 }
  48. 48
  49. 49 }
  50. 50
  51. 51 if(n>=200)
  52. 52 printf("3\n");
  53. 53 else
  54. 54 {
  55. 55 // memset(path,-1,memset(path));
  56. 56 for(int i=1;i<=m;i++)
  57. 57 for(int j=1;j<=m;j++)
  58. 58 {
  59. 59 if(a[i]&a[j])
  60. 60 path[i][j]=1;
  61. 61 }
  62. 62 ll ans=1ll*inf;
  63. 63 for(int i=1;i<=m;i++)//遍历每个点的最小环的长度
  64. 64 {
  65. 65 memset(vis,0,sizeof(vis));
  66. 66 cost=1ll*inf;
  67. 67 dfs(i,1,i);
  68. 68 ans=min(ans,cost);
  69. 69 }
  70. 70
  71. 71 cout << (ans == inf ? -1 : ans) << endl;
  72. 72 }
  73. 73 }

借鉴的原文链接:https://blog.csdn.net/qq\_41608020/article/details/99716916

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long LL;
  4. const int N = 1e5 + 5;
  5. const int inf = 0x3f3f3f3f;
  6. int n, m, mp[500][500];
  7. LL a[N], b[N], ans = 1LL * inf, now;//1LL 是为了在计算时,把int类型的变量转化为long long,然后再赋值给long long类型的变量。
  8. bool vis[500];
  9. void dfs(int u, int w, int rt) { //w表示该路径的边的数目 u表示路径现在走到的点 rt表示枚举的这个环的起点也即终点
  10. vis[u] = 1;
  11. if(w > now) return; //所走的步数大于之前存的最短路径
  12. if(w >= 3 && mp[u][rt]) { //说明走的路径形成环
  13. now = w;
  14. return;
  15. }
  16. for(int v = 1; v <= m; v++) { //可走的路径
  17. if(mp[u][v] && vis[v] == 0 && v != rt){
  18. dfs(v, w + 1, rt);
  19. vis[v] = 0;
  20. }
  21. }
  22. }
  23. int main() {
  24. scanf("%d", &n);
  25. for(int i = 1; i <= n; i++) {
  26. scanf("%lld", &a[i]);
  27. if(a[i]) b[++m] = a[i];//b数组存非0的所以数字
  28. }
  29. if(m >= 200) puts("3"); //这个是大佬们发现的规律吧
  30. else {
  31. for(int i = 1; i <= m; i++)
  32. for(int j = 1; j <= m; j++)
  33. if(b[i] & b[j]) mp[i][j] = 1; //说明节点i,j被连接
  34. for(int i = 1; i <= m; i++) { //枚举环的起点
  35. memset(vis, 0, sizeof vis);
  36. now = inf;
  37. dfs(i, 1, i); //路径当前所走到的点 路径点的个数 路径起点
  38. ans = min(ans, now);//获得最短的周期
  39. }
  40. cout << (ans == inf ? -1 : ans) << endl;
  41. }
  42. }

转载于:https://www.cnblogs.com/Aiahtwo/p/11376541.html

发表评论

表情:
评论列表 (有 0 条评论,164人围观)

还没有评论,来说两句吧...

相关阅读

    相关 codeforces-round375-div2

    题目链接:[codeforces round 375 div2][] A题: 读一遍题目就知道是超级水的题目,,就是给你三个坐标,求三个坐标汇集到一个点所走的路程