• 2022“杭电杯”中国大学生算法设计超级联赛(6)


    Maex 

    有一棵以1为根节点的树,给每个节点赋一个值,从0开始到n-1,定义函数b[i]是以i为根节点的子树的MEX值,求从1~n每个b[i]值最大的和,MEX是在一个集合中没有出现过的最小的自然数。

    思路:我们可以知道,最后b[1]一定是n,而怎样最大化其他节点的b值呢?从0开始辅助,我们可以很显然的知道0从最深的数的节点位置开始赋值一定是最优的,这样最深的这一棵树种每个节点的b值是它的子树的大小。这样考虑会发现,这个题的实质是求每个节点子树的大小,从第一个节点开始,每次加子树最大的那个节点,一直向下走即可。

    AC Code:

    1. #include
    2. typedef long long ll;
    3. const int N=5e5+5;
    4. int t,n;
    5. std::vector<int>vec[N];
    6. ll ans;
    7. ll deep[N];
    8. bool vis[N];
    9. void getdeep(int u){
    10. vis[u]=true;
    11. int len=vec[u].size();
    12. if(len==1&&u!=1){
    13. deep[u]=1;
    14. return;
    15. }
    16. for(int i=0;i
    17. int v=vec[u][i];
    18. if(!vis[v]){
    19. getdeep(v);
    20. deep[u]+=deep[v];
    21. }
    22. }
    23. deep[u]++;
    24. }
    25. void getans(int u,ll tmp){
    26. vis[u]=true;
    27. int len=vec[u].size();
    28. if(len==1&&u!=1){
    29. ans=std::max(ans,tmp+deep[u]);
    30. return;
    31. }
    32. for(int i=0;i
    33. int v=vec[u][i];
    34. if(!vis[v]){
    35. getans(v,tmp+deep[u]);
    36. }
    37. }
    38. }
    39. int main(){
    40. std::ios::sync_with_stdio(false);
    41. std::cin.tie(0);
    42. std::cout.tie(0);
    43. std::cin>>t;
    44. while(t--){
    45. std::cin>>n;
    46. for(int i=1;i<=n;i++){
    47. vec[i].clear();
    48. vis[i]=false,deep[i]=0;
    49. }
    50. for(int i=1;i
    51. int u,v;
    52. std::cin>>u>>v;
    53. vec[u].push_back(v);
    54. vec[v].push_back(u);
    55. }
    56. getdeep(1);
    57. for(int i=1;i<=n;i++){
    58. vis[i]=false;
    59. }
    60. ans=deep[1];
    61. getans(1,0);
    62. std::cout<'\n';
    63. }
    64. return 0;
    65. }

     os:签到都这样了么。。。

    Loop

    给出一个数组a,每次可以把一个数字移到数组后面,经过k次操作,求可以得到的最小字典序的数组a是什么。 

    思路:我们可以贪心的去利用这k次操作,用优先队列从头开始每次维护小于队首的数,最多可以维护k次,在优先队列里存这些要维护的数字,剩下的存到一个数组中,最后归并一下就可以了。

    AC Code:

    1. #include
    2. typedef long long ll;
    3. typedef std::pair<int,int>PII;
    4. const int N=3e5+5;
    5. int t,n,k,num,top;
    6. int a[N],s[N],b[N];
    7. int main(){
    8. std::ios::sync_with_stdio(false);
    9. std::cin.tie(0);
    10. std::cout.tie(0);
    11. std::cin>>t;
    12. while(t--){
    13. std::cin>>n>>k;
    14. top=0,num=0;
    15. for(int i=1;i<=n;i++){
    16. std::cin>>a[i];
    17. }
    18. std::priority_queue<int>q;
    19. for(int i=1;i<=n;i++){
    20. while(top&&s[top]
    21. q.push(s[top]);
    22. top--;
    23. k--;
    24. }
    25. s[++top]=a[i];
    26. }
    27. for(int i=1,l=1;i<=n;i++){
    28. if(l>top){
    29. b[++num]=q.top();
    30. q.pop();
    31. }
    32. else if(q.empty()){
    33. b[++num]=s[l];
    34. l++;
    35. }
    36. else{
    37. if(q.top()>s[l]){
    38. b[++num]=q.top();
    39. q.pop();
    40. }
    41. else{
    42. b[++num]=s[l];
    43. l++;
    44. }
    45. }
    46. }
    47. for(int i=1;i<=n;i++){
    48. std::cout<" \n"[i==n];
    49. }
    50. }
    51. return 0;
    52. }

    os:不太懂出这个题是想干什么,觉得很怪

    Planar Graph

    给出一个图,要求在边上修通路,即打断这条边,使得剩下的成为一棵最小生成树,但是要求输出字典序最小的边,那就需要生成字典序最大的最小生成树。

    思路:就是最小生成树,Kruskal即可,注意留下的是权值大的,所以倒着取数。

    AC Code:

    1. #include
    2. typedef long long ll;
    3. typedef std::pair<int,int>PII;
    4. const int N=3e5+5;
    5. int t,n,m;
    6. std::vectorvec;
    7. int fa[N];
    8. void init(){
    9. for(int i=1;i<=n;i++){
    10. fa[i]=i;
    11. }
    12. }
    13. int getfa(int x){
    14. return fa[x]==x?x:fa[x]=getfa(fa[x]);
    15. }
    16. int main(){
    17. std::ios::sync_with_stdio(false);
    18. std::cin.tie(0);
    19. std::cout.tie(0);
    20. std::cin>>t;
    21. while(t--){
    22. std::cin>>n>>m;
    23. vec.clear();
    24. init();
    25. for(int i=1;i<=m;i++){
    26. int u,v;
    27. std::cin>>u>>v;
    28. vec.push_back({u,v});
    29. }
    30. std::vector<int>ans;
    31. for(int i=m-1;i>=0;i--){
    32. int xx=getfa(vec[i].first),yy=getfa(vec[i].second);
    33. if(xx==yy) ans.push_back(i+1);
    34. else fa[xx]=yy;
    35. }
    36. int len=ans.size();
    37. std::cout<'\n';
    38. for(int i=len-1;i>=0;i--){
    39. std::cout<' ';
    40. }
    41. std::cout<<'\n';
    42. }
    43. return 0;
    44. }

     os:图论就很强,对于这种处理模型的能力要求很高,,看这个题代码思路并不难,但是要把这个题意转变成最小生成树。这个卡行末空格啥东西啊,有什么大病一样QAQ

    Map

     现有一张大地图和一张等比例缩小的小地图,将这张小地图随意放到大地图中,必然存在一个点与大地图上同一位置的点重合,求这个点。

    思路:可以这样考虑:图中满足这个条件的点分别向大小地图的四个顶点连边,他们的比例是等于边长的比例的,根据这个性质推计算公式。

    AC Code:

    代码还没想好怎么写,,这两天想明白了补上。。。

    Shinobu loves trip

    给定一个常数a和p,有个人会进行n次旅行,每次旅行的起点是s[i],第一天的位置在s[i],接下来每一天的位置都会变成s[i]*^(天数)%P。有q个询问,每次询问一个位置x,请问该人有多少次旅游经过了x。 

    思路:学习大佬的思路

    先观察数据范围,d<=20000,n<=1000,q<=1000。很容易想到对于一个x,我们枚举每一次旅游,从小到大寻找20000次,直到找到符合条件的答案或者进入死循环退出,但是时间复杂度显然不允许。因此我们可以预处理出所有的a^k直接查询,这样是没问题的。

    s[i] * a^k % P = x。这个式子我们能够处理出a^k,因此我们考虑分离变量,a^k=x/s[i]modP。我们知道s[i]和x,因此我们可以直接计算出a^k,然后在我们预处理出的map中查,用限制天数d判断是否符合条件即可。时间复杂度O(nq)=1e6,理论上能过。

    AC Code:

    1. #include
    2. #include
    3. #define int long long
    4. const int N=1e3+5;
    5. int t,P,n,a,q,ans;
    6. int s[N],d[N],fact[N];
    7. int pmod(int a,int b){
    8. int res=1;
    9. while(b){
    10. if(b&1) res=res*a%P;
    11. b>>=1;
    12. a=a*a%P;
    13. }
    14. return res;
    15. }
    16. signed main(){
    17. std::ios::sync_with_stdio(false);
    18. std::cin.tie(0);
    19. std::cout.tie(0);
    20. std::unordered_map<int,int>mp;
    21. std::cin>>t;
    22. while(t--){
    23. std::cin>>P>>a>>n>>q;
    24. mp.clear();
    25. int cur=1,pos=0;
    26. while(pos<2e5+5&&!mp.count(cur)){
    27. mp[cur]=pos;
    28. cur=cur*a%P;
    29. pos++;
    30. }
    31. for(int i=1;i<=n;i++){
    32. std::cin>>s[i]>>d[i];
    33. if(s[i]) fact[i]=pmod(s[i],P-2);
    34. }
    35. while(q--){
    36. int x;
    37. std::cin>>x;
    38. ans=0;
    39. if(x==0){
    40. for(int i=1;i<=n;i++){
    41. if(!s[i]) ans++;
    42. }
    43. }
    44. else{
    45. for(int i=1;i<=n;i++){
    46. if(s[i]!=0){
    47. int r=x*fact[i]%P;
    48. if(mp.count(r)&&mp[r]<=d[i])
    49. ans++;
    50. }
    51. }
    52. }
    53. std::cout<'\n';
    54. }
    55. }
    56. return 0;
    57. }

    os:注意这样写的时限卡的很紧,必须用unordered_map才能过,而且头文件也不能用万能头,要分开写,就离谱,感觉复杂度是完全可以过的,难道因为常数大吗???

    先这样吧QWQ

  • 相关阅读:
    MySQL三大日志——binlog、redoLog、undoLog详解
    我如何使用工具学习网络技术?
    区间信息维护与查询【线段树 】 - 原理2 线段树中的“懒操作”
    揭秘华为云GaussDB(for Influx)最佳实践:hint查询
    【Unity脚本】使用脚本操作游戏对象的组件
    关于前端开发中导入导出
    【高质量C/C++】5.常量
    ElasticSearch从入门到精通:常用操作
    macOS系统下载IDEA的操作流程
    接口与抽象类的区别
  • 原文地址:https://blog.csdn.net/m0_62289613/article/details/126691561