北方大学训练赛,第一周

来源:互联网 发布:数据流量怎么打开不了 编辑:程序博客网 时间:2024/04/30 20:38

题目链接。http://dutacm.club:7217/codesheaven/contest.php?cid=1019

这次一道也不会。哎有点烦。

但是从最简单的题学了一下矩阵快速幂。

先给出举办方给出的题解吧。等我会了再慢慢看吧。

题解

A. 生成树计数。树的Prufer序列包含且仅包含所有的非叶子节点,问题化为求图 GG 的每个节点在多少棵生成树中是叶子节点。这个问题可以用矩阵树定理来做。

B. 不难想到这样一个网络流模型:从源点出发到每个星球连一条有向边,容量为 p[i]p[i],从每个星球出发到汇点连一条有向边,容量为 s[i]s[i],每对星球之间从编号较小的星球出发到编号较大的星球连一条有向边,容量为 cc。求得的最大流即为答案。
但这个图的规模太大了,直接跑 Dinic 算法并不现实。由最大流最小割定理,我们转向求最小割。
可以使用DP求最小割。状态转移方程为
dp[i][j]=min(dp[i1][j1]+s[i],dp[i1][j]+p[i]+j×c)dp[i][j]=min(dp[i−1][j−1]+s[i],dp[i−1][j]+p[i]+j×c)
其中 dp[i][j]dp[i][j] 代表的含义是:对于源点、汇点、和前 ii 个城市组成的网络流,割集包含 jj 个节点(不算源点)时的最小割,所以 min{dp[n][j]}min{dp[n][j]} 即为答案。
但是这个解法的复杂度为 On2O(n2),不足以通过本题。我们发现,割集每多包含一个节点,割值都会加上 p[i]s[i]+c×(ik)p[i]−s[i]+c×(i−k),其中i是本次被加入割集的节点,kk 是这个割集中已有多少个节点。于是我们想到这样的贪心优化:对每个节点ii定义 w[i]=p[i]s[i]+c×iw[i]=p[i]−s[i]+c×i,并对 w[i]w[i] 排序,从 w[i]w[i] 较小的节点开始将节点加入割集,即可求得割集包含 kk个节点时的最小割。取最小值即得答案。
于是,本题的复杂度被优化为了 OnlognO(nlog⁡n)

C. 很容易想的一道题。点光源照射一个水平的圆,在地面上的投影就是一个相似的圆,而这个建筑就是由无数个半径连续变化(每层半径光滑变化)的圆面堆叠而成,所以投影就是另一个由无数个半径连续变化(每层半径光滑变化)的圆重叠而成的阴影面积。借用极限的思想,我们只需取每层的上底面的圆在点光源照射下形成的投影的坐标和半径,然后枚举的求出这些圆的交(也要判断小圆被大圆包括的情况),再求相邻两个圆的公切线,最终的阴影的边界就是由若干圆弧和公切线组成的一个分段函数,我们就可以轻松地用不同方式求分段函数的积分乘 22 就可以了(不过看到一种简洁的求法,用Simpson积分精度试了试到 10510−5,也可以纯几何做)。

D. 二分答案。将 AABB 两数组分别排序,可使用双指针,即两个指针一个在 AA 上一个在 BB 上,AA 上指针从小到大走,BB 上指针从大到小走。这样对于每个二分出的答案 midmid 可以 O(n+m)O(n+m) 时间内求出小于 midmid 的 CC数组元素的个数。

E. 矩阵快速幂。不难写出转移矩阵。

F. 区间 [L,R][L,R] 内的数排序后构成等差数列可分两种情况

  1. 公差为 00
  2. 公差不为 00  区间内无相同元素 且 相邻两项差构成的数列的GCD ××RLR−L) = (区间最大值-区间最小值)
下面补一下快速幂的模板

const int N=10;  int tmp[N][N];  void multi(int a[][N],int b[][N],int n)  {      memset(tmp,0,sizeof tmp);      for(int i=1;i<=n;i++)          for(int j=1;j<=n;j++)          for(int k=1;k<=n;k++)          tmp[i][j]+=a[i][k]*b[k][j];      for(int i=1;i<=n;i++)          for(int j=1;j<=n;j++)          a[i][j]=tmp[i][j];  }  int res[N][N];  void Pow(int a[][N],int n)  {      memset(res,0,sizeof res);      for(int i=1;i<=n;i++) res[i][i]=1;      while(n)      {          if(n&1)              multi(res,a,n);//res=res*a;复制直接在multi里面实现了;          multi(a,a,n);//a=a*a          n>>=1;      }  }  

感谢来源:http://blog.csdn.net/wust_zzwh/article/details/52058209?locationNum=1&fps=1;

最后是学校大佬赵巨巨写的。http://paste.ubuntu.com/24118319/


0 0