• 第46屆ICPC 東亞洲區域賽(澳門)


    题目:A.So I'll Max Out My Constructive Algor...

    题目链接:登录—专业IT笔试面试备考平台_牛客网

    样例输入: 

    1. 1
    2. 2
    3. 4 3
    4. 2 1

    样例输出:

    4 3 1 2

    题意:给定一个n*n的二维格点,每个格点有一个高度,任意两个格点的高度都是互不相同的,现在让我们找到一条路径使得这条路径经过所有的点一次,而且要保证路径中爬坡的次数要小于等于下坡的次数。

    分析:其实我们发现题目中要求的条件非常弱,因为路径中爬坡的次数要么小于等于下坡的次数,要么就是大于下坡的次数,只有这两种情况,我们可以随便找一条路径,如果这条路径满足题目要求那么我们就输出这条路径,否则就反向输出这条路径

    1. #include<cstdio>
    2. #include<iostream>
    3. #include<algorithm>
    4. #include<cstring>
    5. #include<map>
    6. #include<queue>
    7. #include<vector>
    8. #include<cmath>
    9. using namespace std;
    10. const int N=103;
    11. int a[N][N];
    12. int main()
    13. {
    14. int T;
    15. cin>>T;
    16. while(T--)
    17. {
    18. int n;
    19. scanf("%d",&n);
    20. for(int i=1;i<=n;i++)
    21. for(int j=1;j<=n;j++)
    22. scanf("%d",&a[i][j]);
    23. vector<int>p;
    24. for(int i=1;i<=n;i++)
    25. {
    26. if(i&1)
    27. for(int j=1;j<=n;j++)
    28. p.push_back(a[i][j]);
    29. else
    30. for(int j=n;j>=1;j--)
    31. p.push_back(a[i][j]);
    32. }
    33. long long cnt=0;
    34. for(int i=1;i<p.size();i++)
    35. cnt+=p[i]>p[i-1];
    36. if(cnt<=(1ll*n*n-1)/2)
    37. for(int i=0;i<p.size();i++)
    38. {
    39. printf("%d",p[i]);
    40. if(i!=p.size()-1)
    41. printf(" ");
    42. }
    43. else
    44. for(int i=p.size()-1;i>=0;i--)
    45. {
    46. printf("%d",p[i]);
    47. if(i!=0)
    48. printf(" ");
    49. }
    50. puts("");
    51. }
    52. return 0;
    53. }

    F.Sandpile on Clique

    题目链接:登录—专业IT笔试面试备考平台_牛客网

    样例1输入:

    1. 5
    2. 5 0 3 0 3

    样例1输出:

    3 3 1 3 1

    样例2输入:

    1. 2
    2. 1 0

    样例2输出:

    Recurrent

    简化题意:给定n个数,如果有一个数的值大于等于n-1,那么它就要将值减n-1,然后其余所有数的值都加1,问最后能不能使得数组恒定。如果能输出恒定数组,否则输出Recurrent

    分析:如果数组最终能恒定那么操作的次数一定不会大于n-1,如果数组进行了n次操作,而一共有n个数,那么至少有一个数会+(n-1),因为n次操作代表平均每个数进行一次操作,也就是值减少n-1,那么也就是说一定存在一个数进行操作的次数是小于等于1的。那么它的值增加至少n-1,那么它又可以继续操作,按照这个方法推下去发现可以一直进行操作。

    当然还有一种理解方式,就是我们可以发现无论对于哪个数进行一次操作,所有位置的数都会发生改变,那么如果某个位置的数出现了之前出现过的数,那么就说明存在循环节,因为这个时候除了这个位置以外的其他数也一定与之前完全相同,因为我们没办法只操作n-1个数,因为每个数最后的合理取值只有0~n-2,所以n-1就是最大循环节。

    也就是判断总的操作次数是否大于等于n,如何判断当前数组是否还能继续操作呢?其实就是判断数组中的最大值是否大于等于n-1,这个我们可以直接用线段树来维护,对某个位置进行操作就等价于将这个点的值减少n-1,其余点的值+1,这个复杂度都是O(logn)的,所以总的复杂度就是O(nlogn)。

    细节见代码:

    1. #include<cstdio>
    2. #include<iostream>
    3. #include<algorithm>
    4. #include<cstring>
    5. #include<map>
    6. #include<queue>
    7. #include<vector>
    8. #include<cmath>
    9. using namespace std;
    10. const int N=2e5+10;
    11. int fu[N],du[N];
    12. bool vis[N];//vis[i]=true/false表示第i号点在/不在环中
    13. struct node{
    14. int u,v;
    15. }p[N];
    16. int find(int x)
    17. {
    18. if(x!=fu[x]) return fu[x]=find(fu[x]);
    19. return fu[x];
    20. }
    21. vector<int>pp[N];
    22. int main()
    23. {
    24. int T;
    25. cin>>T;
    26. while(T--)
    27. {
    28. int n,m;
    29. scanf("%d%d",&n,&m);
    30. for(int i=1;i<=n;i++)
    31. fu[i]=i,vis[i]=false,du[i]=0,pp[i].clear();
    32. bool flag=false;
    33. for(int i=1;i<=m;i++)
    34. scanf("%d%d",&p[i].u,&p[i].v);
    35. for(int i=1;i<=m;i++)
    36. {
    37. int f1=find(p[i].u),f2=find(p[i].v);
    38. du[p[i].u]++;du[p[i].v]++;
    39. pp[p[i].v].push_back(p[i].u);
    40. pp[p[i].u].push_back(p[i].v);
    41. if(f1!=f2) fu[f1]=f2;
    42. else
    43. {
    44. flag=true;//找到环
    45. queue<int>q;
    46. for(int j=1;j<=n;j++)
    47. {
    48. if(du[j]) vis[j]=true;
    49. if(du[j]==1) q.push(j);
    50. }
    51. while(!q.empty())
    52. {
    53. int t=q.front();
    54. vis[t]=false;
    55. q.pop();
    56. for(int j=0;j<pp[t].size();j++)
    57. {
    58. du[pp[t][j]]--;
    59. if(du[pp[t][j]]==1) q.push(pp[t][j]);
    60. }
    61. }
    62. for(int j=1;j<=i;j++)
    63. if(vis[p[j].u]&&vis[p[j].v]) printf("%d ",j);
    64. puts("");
    65. break;
    66. }
    67. }
    68. if(!flag) puts("-1");
    69. }
    70. return 0;
    71. }

    K.Link-Cut Tree

    题目链接:登录—专业IT笔试面试备考平台_牛客网

    样例输入:

    1. 2
    2. 6 8
    3. 1 2
    4. 2 3
    5. 5 6
    6. 3 4
    7. 2 5
    8. 5 4
    9. 5 1
    10. 4 2
    11. 4 2
    12. 1 2
    13. 4 3

    样例输出:

    1. 2 4 5 6
    2. -1

    题意:给定一张图,包含n个点和m条边,第i条边的边权是2^i,让我们在图中找到一个边权和最小的环,如果能找到就输出这个环上的边的编号,否则输出-1.

    分析:这道题直接贪心就行,我们知道\sum_{i=1}^{n}2^i=2^(n+1)-2,也就是说前i条边的边权和不如第i+1条边的边权和大。那么很容易能够想到我们应该尽量用编号小的边组成环,那么我们直接利用kruscal求最小生成树的思想直接从编号小的边开始建图,直至出现环为止,这个时候我们就形成了一个新的带环图,然后我们用拓扑排序把不在环上的点全部删掉,然后利用环上的点求一下环上的边即可。求的方法很简单,就是直接看一下当前在图上的边有哪些,选出来边的两端的点都是环上的点的边输出即可

    细节见代码:

    1. #include<cstdio>
    2. #include<iostream>
    3. #include<algorithm>
    4. #include<cstring>
    5. #include<map>
    6. #include<queue>
    7. #include<vector>
    8. #include<cmath>
    9. using namespace std;
    10. const int N=2e5+10;
    11. int fu[N],du[N];
    12. bool vis[N];//vis[i]=true/false表示第i号点在/不在环中
    13. struct node{
    14. int u,v;
    15. }p[N];
    16. int find(int x)
    17. {
    18. if(x!=fu[x]) return fu[x]=find(fu[x]);
    19. return fu[x];
    20. }
    21. vector<int>pp[N];
    22. int main()
    23. {
    24. int T;
    25. cin>>T;
    26. while(T--)
    27. {
    28. int n,m;
    29. scanf("%d%d",&n,&m);
    30. for(int i=1;i<=n;i++)
    31. fu[i]=i,vis[i]=false,du[i]=0,pp[i].clear();
    32. bool flag=false;
    33. for(int i=1;i<=m;i++)
    34. scanf("%d%d",&p[i].u,&p[i].v);
    35. for(int i=1;i<=m;i++)
    36. {
    37. int f1=find(p[i].u),f2=find(p[i].v);
    38. du[p[i].u]++;du[p[i].v]++;
    39. pp[p[i].v].push_back(p[i].u);
    40. pp[p[i].u].push_back(p[i].v);
    41. if(f1!=f2) fu[f1]=f2;
    42. else
    43. {
    44. flag=true;//找到环
    45. queue<int>q;
    46. for(int j=1;j<=n;j++)
    47. {
    48. if(du[j]) vis[j]=true;
    49. if(du[j]==1) q.push(j);
    50. }
    51. while(!q.empty())
    52. {
    53. int t=q.front();
    54. vis[t]=false;
    55. q.pop();
    56. for(int j=0;j<pp[t].size();j++)
    57. {
    58. du[pp[t][j]]--;
    59. if(du[pp[t][j]]==1) q.push(pp[t][j]);
    60. }
    61. }
    62. for(int j=1;j<=i;j++)
    63. if(vis[p[j].u]&&vis[p[j].v]) printf("%d ",j);
    64. puts("");
    65. break;
    66. }
    67. }
    68. if(!flag) puts("-1");
    69. }
    70. return 0;
    71. }
  • 相关阅读:
    (十四)数据结构-图
    count(*)查询性能很差?用这5招轻松优化
    JavaScript字符串常用方法
    day04-1群聊功能
    元数据管理-解决方案调研二:元数据管理解决方案——Saas/内部解决方案(1)
    jvm参数设置方法(win10)
    rabbitmq-java-client源码结构设计与分析
    国外大神制作的史上最精简Win10系统,真有那么好用吗?
    goroutine 调度
    基础生态学终结版复习题
  • 原文地址:https://blog.csdn.net/AC__dream/article/details/127785658