NOIP 模拟八

T1:星际旅行:

  显然根据题目要求,我们能想到该问题可以转化为存在多少种情况,使得删去两条边后存在一条路径可以经过每条边两次

显然有等价于存在一条路径可以经过每条边一次,那么问题显然就是判断是否存在(无向图)欧拉路

然而考场上考虑的却是用Tarjan判断上述条件,显然错误,原因在于基础不牢固并且对于算法本质认识不清

不能在任一情况下应用合适的算法解决问题。

  返回正题:欧拉路判断方法:

  欧拉路径:
        无向图:连通,点的度数全为偶数(此时所有点均可以为起点,因为相当于欧拉回路),或者只有两个点度数为奇数(只有度数为奇数的点才可以为起点)
        有向图:出度和入度相等(所有点可以为起点),或者只有两个点:其中一个入度+1=出度(起点),另一个出度+1=入度(终点)
     欧拉回路
        无向图:连通,点的度数全为偶数(所有点可以为起点)。
        有向图:出度和入度相等(所有点可以为起点)。
     图论问题中首先要注意重边与自环:重边可利用成对变换判断解决,而自环根据情况可以在输入时continue,而本题显然不能如此
也就是要考虑重边影响,在明确欧拉路判断方法后,此问题显然转化成了一个计数问题,也就是删掉两条边后使得无向图存在0个或2个节点度数为奇数

分别考虑删去两自环,一自环一边,和两边,判断存在多少种删法满足要求(注意首先要判断图的连通性,因为欧拉路的判断是基于图的连通性进行的)。

代码如下:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define I long long
 4 #define B bool
 5 #define C char
 6 #define RE register
 7 #define V void
 8 #define L inline
 9 const I MAXN = 1e5 + 10;
10 I n,m,x,y,pd,res,num[MAXN],outit[MAXN];
11 B jud[MAXN];
12 struct Disjoint_set{
13     I father[MAXN],self[MAXN],tot[MAXN];
14     V initial() {   for(RE I i(1);i <= n; ++ i) father[i] = i;  }
15     I find(I x) {   return x == father[x] ? x : father[x] = find(father[x]);    }
16     V merge(I x,I y){   
17         I fx = find(x); I fy = find(y);
18         if(fx != fy)    father[fy] = fx,self[fx] += self[fy];
19     }
20 }Disjoint_set;
21 L I read(); L I fir(I); L I ope(I); 
22 signed main(){
23     n = read(); m = read();
24     Disjoint_set.initial();   
25     for(RE I i(1);i <= m; ++ i){
26         x = read(); y = read();
27         if(x == y)  {   Disjoint_set.self[Disjoint_set.find(x)]++;  continue;   }
28         Disjoint_set.merge(x,y);  
29         outit[x]++; outit[y]++;    
30     }
31     for(RE I i(1);i <= n; ++ i) {
32         I anc = Disjoint_set.find(i);
33         num[anc] += outit[i];   Disjoint_set.tot[anc] += fir(outit[i]);
34     }
35     for(RE I i(1);i <= n; ++ i) {
36         if(num[i])  pd++;
37         if(pd > 1)  {   printf("0");    return 0;   }
38         num[i] >>= 1;
39     }
40     for(RE I i(1);i <= n; ++ i) {
41         I anc = Disjoint_set.find(i);
42         if(!jud[anc])   jud[anc] = 1,res += ope(anc);
43     }
44     printf("%lld",res);
45 }
46 L I read(){RE I x(0);RE C z(getchar());while(!isdigit(z))z=getchar();while(isdigit(z))x=(x<<3)+(x<<1)+(z^48),z=getchar();return x;}
47 L I fir(I x)    {   return x * (x - 1) / 2 ;    }
48 L I ope(I x){  
49     Disjoint_set.tot[x] += fir(Disjoint_set.self[x]);
50     Disjoint_set.tot[x] += Disjoint_set.self[x] * num[x];
51     return Disjoint_set.tot[x];
52 }
View Code

 

T2:砍树:

  首先反思做题思路:拿到一道题首先要观察数据范围,根据数据范围判断时空复杂度范围进而确定大致的算法类型,其次应该先判断题目类型是否为数学题,

如若通过推导难以解决那么尝试用数据结构解决问题

  进入正题:根据数据范围我们可以考虑log类型复杂度,然而考虑数据做法的话无从下手

此时考虑数学解法,对于信息类问题的数学解法首先要对问题进行数学抽象,该问题可以转化为:

  求一个最大的d,满足:sigma(ceil(ai/d)*d-ai)<=k,令C=k+sigma(ai),移项得sigma(ceil(ai/d))*d<=C;

显然右侧是一个定值(分离包含多个变量的项,使公式中不同变量之间相互独立的思想),再移项得sigma(ceil(ai/d))<=C/d;

分析发现右侧是一个分段函数,回归问题我们要求满足该不等式最大的d,我们发现对于分段函数上的每一段,右端点显然是最优解,

这理解涉及如何去枚举,如果枚举分段函数纵坐标来计算每一段的右端点,那么时间复杂度为O(sigma),显然会超时,分析发现如果我们直接枚举

右端点进行转移会省去很多不必要的枚举降低复杂度(O(sqrt(k+max(ai)))),也就是说在枚举过程中,我们要尽量类似此题跳跃性枚举来减少不必要的操作,

当然这需要枚举变量间存在一定的递推关系。

代码如下:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 #define I unsigned long long
 7 #define B bool
 8 #define C char
 9 #define RE register
10 #define V void
11 #define L inline
12 I n,k,maxn,sigma,tall[105];
13 L I read(); L I up(I,I); L I fir(I); 
14 signed main(){
15     n = read(); k = read(); sigma += k; maxn += k; 
16     for(RE I i(1);i <= n; ++ i) tall[i] = read(),sigma += tall[i];
17     maxn += *max_element(tall + 1,tall + n + 1); 
18     for(RE I i(sigma / (sigma / maxn)); i ;i = sigma / (sigma / i + 1))
19         if(fir(i) <= sigma / i) {   printf("%lld",i);break;  }
20 }
21 L I read(){RE I x(0);RE C z=getchar();while(!isdigit(z))z=getchar();while(isdigit(z))x=(x<<3)+(x<<1)+(z^48),z=getchar();return x;}
22 L I up(I x,I y) {   return x % y ? x / y + 1 : x / y ;  }
23 L I fir(I x){   I res(0);
24     for(RE I j(1);j <= n; ++ j)
25         res += up(tall[j],x);
26     return res;
27 }
View Code

 

posted @ 2021-06-22 21:12  HZOI_LYM  阅读(43)  评论(0编辑  收藏  举报