2012 MultiUniversity Training Contest 3

1001  HDU4320  Arcane Numbers 1

GCD 0MS 无压力 

代码: 

View Code 
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #define LL __int64
 5 using namespace std;
 6 LL gcd(LL a,LL b)
 7 {
 8     return b==0?a:gcd(b,a%b);
 9 }
10 int main()
11 {
12     LL a,b,c;
13     int t,k=0;
14     scanf("%d",&t);
15     while(t--)
16     {
17         k++;
18         scanf("%I64d%I64d",&a,&b);
19         c=gcd(a,b);
20         while(c>1)
21         {
22             a/=c;
23             c=gcd(a,b);
24         }
25         printf("Case #%d: ",k);
26         if(a==1)
27             puts("YES");
28         else
29             puts("NO");
30     }
31     return 0;
32 }
33


1005  HDU4324  Trangle LOVE

人人上有个神人说  直接计算每个点出度,没有两个出度相等的情况下为NO,其他为YES,就过了。果然如此。。。。

代码: 


View Code 
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 int main()
 7 {
 8     int a[2001];
 9     int i,j,k=0,t,n,flag;
10     char b;
11     scanf("%d",&t);
12     while(t--)
13     {
14         memset(a,0,sizeof(a));
15         flag=0;
16         k++;
17         scanf("%d",&n);
18         for(i=0;i<n;i++)
19         {
20             getchar();
21             for(j=0;j<n;j++)
22             {
23                 b=getchar();
24                 if(b=='1')
25                 {
26                     a[i]++;
27                 }
28             }
29         }
30         sort(a,a+n);
31         for(i=0;i<n-1;i++)
32         {
33             if(a[i]==a[i+1])
34             {
35                 flag=1;
36                 break;
37             }
38         }
39         printf("Case #%d: ",k);
40         if(flag)
41             puts("Yes");
42         else
43             puts("No");
44     }
45     return 0;
46 }
47



1006  HDU4325  Flowers

比较裸的区间更新的线段树

代码:

View Code 
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 #define lson l,m,rt<<1
 6 #define rson m+1,r,rt<<1|1
 7 #define LL __int64
 8 const int N=100002;
 9 LL add[N<<2];
10 LL sum[N<<2];
11 void pushup(LL rt)
12 {
13     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
14 }
15 void pushdown(LL rt,LL m)
16 {
17     if(add[rt]) 
18     {
19         add[rt<<1]+=add[rt];
20         add[rt<<1|1]+=add[rt];
21         sum[rt<<1]+=add[rt]*(m-(m>>1));
22         sum[rt<<1|1]+=add[rt]*(m>>1);
23         add[rt]=0;
24     }
25 }
26 void build(LL l,LL r,LL rt) 
27 {
28     add[rt]=0;
29     if(l==r) 
30     {
31         sum[rt]=0;
32         return ;
33     }
34     int m=(l+r)>>1;
35     build(lson);
36     build(rson);
37     pushup(rt);
38 }
39 void update(LL L,LL R,LL c,LL l,LL r,LL rt) 
40 {
41     if(L<=l&&r<=R) 
42     {
43         add[rt]+=c;
44         sum[rt]+=(LL)c*(r-l+1);
45         return ;
46     }
47     pushdown(rt,r-l+1);
48     LL m=(l+r)>>1;
49     if(L<=m) 
50         update(L,R,c,lson);
51     if(m<R) 
52         update(L,R,c,rson);
53     pushup(rt);
54 }
55 LL query(LL L,LL R,LL l,LL r,LL rt) 
56 {
57     if(L<=l&&r<=R) 
58     {
59         return sum[rt];
60     }
61     pushdown(rt,r-l+1);
62     LL m=(l+r)>>1;
63     LL ret=0;
64     if(L<=m) 
65         ret+=query(L,R,lson);
66     if(m<R) 
67         ret+=query(L,R,rson);
68     return ret;
69 }
70 int main() 
71 {
72     int t,k=0;
73     scanf("%d",&t);
74     while(t--)
75     {
76         k++;
77         int i,j;
78         __int64 a,b,c,d;
79         scanf("%I64d%I64d",&a,&b);
80         build(1,N,1);
81         for(i=0;i<a;i++)
82         {
83             scanf("%I64d%I64d",&c,&d);
84             update(c,d,1,1,N,1);
85         }
86         printf("Case #%d:\n",k);
87         for(j=0;j<b;j++)
88         {
89             scanf("%I64d",&c);
90             printf("%I64d\n",query(c,c,1,N,1));
91         }
92     }
93     return 0;
94 }
95

附:

官方题解:

1001
检查A中的质因子 是否都在 B中被包含。
1002
按位统计计算,如果枚举 那么复杂度就是 64 * N
第一条
当统计第K位的时候 可以注意到 第 B+T*A  和 B+(T+2^(K+1))*A 位是相同的
那么 第K位的时候 只需要统计2^K 次就可以了 
第二条
当统计第K位的时候 可以注意到 连续的 (2^K)/A都是连续的0 或者连续的1 所以可以考虑直接连续记录(2^K)/A个结果。                
那么 第K位的时候 只需要统计N / ((2^K)/A)次就可以了                 
综合 第一条 第二条  那么 第K位的时候 只需要统计 2^K/((2^K)/A) 复杂度 变为O(A)              
总复杂度为64*A
 
1003

【题目大意】

有N颗糖果和M个小孩,老师现在要把这N颗糖分给这M个小孩。每个小孩i对每颗糖j都有一个偏爱度Aij,如果他喜欢这颗糖,Aij = k,否则Aij = 1。小孩i觉得高兴当且仅当ΣCij×Aij >= Bi,j=1,2,…,N,若他分得了糖j,Cij = 1,否则Cij = 0。问能否合理分配这N颗糖,使得每个小孩都觉得高兴。
【建模方法】
(最大费用最大流)
         本题有一个突破点就是:他喜欢这颗糖,Aij = k,否则Aij = 1,关键在于如果他不喜欢这个糖分给他一样可以获得1点的欢乐值。也就是说如果之前分配了的糖给了小孩一定的欢乐值,不够bi,可以直接用随意的糖去填满。
首先我们要求欢喜值>=bi,是否可以认为当我获得欢喜值为bi后,多余欢喜值对这个结果的满足是没有贡献的。也就是说,你可以用一个容量来控制分配糖对小孩欢喜值的控制,让获得欢喜值最多为bi。如果不够,最后用一些1的糖来填满。
而这个容量就是bi/c,获取贡献为k,bi%c(>1)的也是可以用一个能让这个小孩欢喜的糖来贡献,但是其费用只为bi%c。
对于小孩来说,最大费用最大流后,糖分配的贡献值为最大费用,剩余糖就是(n-最大流),然后用这些糖去填不满的,只要满足总和大于Σbj。就可以分配了。
具体建模方案1:
(s,i,1,0);
(i,j,1,0);
(j,t,bj/k,k);
If(bj%k>1)
(j,t,1,bj%k)
Ans = 费用 + N – 最大流 >= Σbj  则满足要求
具体建模方案2:
(s,I,1,0)  
(I,j,1,0)
(j,t,bj/k,k-1);
If(bj%k>1)
(j,t,1,bj%k-1);
Ans = 费用+N  >= Σbj  则满足要求

当k = 2时候,可以不用费用流,最大流即可。

一种最直观的想法就是每颗糖i作为一个点并连边(s, i, ?),每个小孩j作为一个点并连边(j, t, Bj)。若小孩j喜欢糖果i则连边(i, j, 2),否则连边(i, j, 1),然后求一次最大流看是否等于ΣBj。但是问题也很明显,我们还没有给与源点关联的边确定容量。实际上我们无法确定它们的容量,因为最大流无法实现这样一种控制:一个点有若干条出边,容量不尽相同,现在要求经过该点的流可以任选一条出边流走,且一旦选定之后就只能从这条边流而不能再进入其他的出边。因此我们无法确定与源关联的边的容量,因为经过每颗糖i的流无法在出边容量有1又有2的情况下作出正确的选择。
那么是否就没有办法了呢?虽然流无法在容量有1又有2的情况下作出正确的选择,但却可以在容量有1又有0的情况下最自然地作出正确的选择,流过去就表示选择了那条出边,且因为容量为1,不会再有流进入其他的出边。那么此题的构图方法也就出来了:每颗糖i作为一个点并连边(s, i, 1),每个小孩j作为一个点并连边(j, t, floor(Bj/2)),若小孩j喜欢糖果i则连边(i, j, 1),否则连边(i, j, 0)或者干脆不连边,效果一样。设最大流为ans,若ans+N >= ΣBj则可以满足要求。为什么?因为每颗糖迟早都要分给某个小孩,它一定会为总权值贡献1,只不过如果它分给了喜欢它的小孩就再额外贡献1。现在我只考虑这额外的1单位贡献究竟能送出去多少,最后加上基值N并与ΣBj比较即可。
 

1004

这道题求两个字符串编辑距离的部分用动态规划就可以了,如果不加任何优化,总的复杂度是1500*1000*10*10,时间给了1s,如果写的效率比较高,有可能可以水过。
标程的用到了一个叫做BK-Tree的数据结构优化一下,其实原理很简单,可以参考wiki http://en.wikipedia.org/wiki/BK-tree和matrix67的blog http://www.matrix67.com/blog/archives/333
 
1005
题目描述:
2000个点的有向图,保证任意两点间仅有一条有向边。
解题报告:
增量算法,充分利用“任意两点间仅有一条有向边”的性质。
假设前面已经加入了N个点,现在来了第N+1个点。
那么一定能将N个点分成left和right两部分,使得N+1号点到left有边,right到N+1号点右边(因为任意两点间都有边),那么,如果left的任意一个点l到right任意一个点r有边的话,那么就有答案N+1->l->r->N+1这样一个长度为3的环。
那么每次加入N+1号点后,用O(N)的复杂度求出左边的数量leftnum,右边的数量rightnum,left的出度和leftout,left的入度和leftin。
如果left没有一条到right的边,则一定满足:
leftin = leftout + leftnum * rightnum(left和right任意两点右边,如果没有左到右的,那么leftnum*rightnum条边都是右到左的)
那么,如果leftin != leftout + leftnum * rightnum,则暴力枚举左点,右点即可得到答案。
总体复杂度O(n^2)
 
附加一份其他人的解题报告
lengxiang解题报告:
我稍微的看了下出题人的解题报告,没咋看懂。稍微有所启发。写了一个不一样的代码,数据同样通过。
归结为1个条件,任何两人都有边,要么出要么入。
对于有向三元环,我们知道找到:A->B->C->A ,B->C->A->B ,C->A->B->C 是一样的,这给0(n^2)的算法提供了基础。
        对于每次枚举i,我们在(0~i-1)的范围看下有多少个i指向的点(剩下的就是指向i的点),同时算下i指向的点的出度和。就可以知道这些 i指向的点 指向 指向i的点(剩下的点)的数目,如果 
        num * (num - 1) / 2 < sumout 那么就是被指向的点有指出去了,这样就形成了3元环。
        否则,剩下的就是更新下出度即可,继续执行下一个节点。
 
1006
这个题就是比较裸的区间更新,单点查询的线段树。一开始需要把要查询的点和花开的时间和花谢的时间一起离散化了,这样查询的时候就方便多了。
 

1007

本题题意很简单,给出n个人每次4人进行比赛其他人等待,胜者继续,负者排到最后,连续或得m次胜利的人成为最终的赢家,求第k个人最终获得胜利的概率是多少?
对于这题,我们首先确立一个这样的模型: x1先赢了i局,正在于x2,x3,x4赌斗,后面依次有x5,x6,……,xn等待。用P[i][j]表示x1先赢了i局的情况下,当前的xj获胜的概率。
不难得到以下的一些式子:

 i < m

P[i][j] = P[i + 1][j] * 1/4 + P[1][n - 2] * 3/4                                                 j = 1
P[i + 1][n - 2] * 1/4 + P[1][1] * 1/4 + P[1][n - 1] * 2/4                                 j = 2
P[i + 1][n - 1] * 1/4 + P[1][1] * 1/4 + P[1][n - 1] * 1/4 + P[1][n] * 1/4          j = 3
P[i + 1][n] * 1/4 + P[1][1] * 1/4 + P[1][n] * 2/4                                           j = 4
P[i + 1][j - 3] * 1/4 + P[1][j - 3] * 3/4                                                         j>=4
 

i = m

P[i][j] = 1                                                                                                   j = 1
0                                                                                                               j != 1
 

于是我们得到了一个未知数为n*m个的方程组。用高斯消元法解之即可。

值得注意的是,以上思想并不难想到,但是普通的高斯消元法会由于舍入误差使得结果出现很大的偏差,这里我们采用的是分数形式的高斯消元的解法。

 

1008

首先利用旋转卡壳计算出每个点的凸包,由于密度公式非常特殊,则利用公式微积分即可算得每个点落到上面的概率。具体详见代码
 
1009
本题主要考察DP状态转移以及数据结构的使用。相邻块不能相同的最长周长的正方形,直接用O(1)转移的二维dp可以实现,g[i][j]表示右下角选为(i,j)的周长最长正方形,根据图像特性,g[i][j] = min( g[i-1][j] , g[i][j-1] ) or g[i][j] = min( g[i-1][j] , g[i][j-1] ) + 1,是否需要加1取决于对于块的颜色与map(i,j)上的颜色是否相同。
对于周长最长的同色矩形,首先O(n)枚举矩形的下底,然后从左至右O(m)依次枚举相应左右边界的最大值,枚举工作使用队列提速,询问过程涉及到区间更新区间查询的功能,使用线段树优化查询效率,复杂度O(n * m * lg(n)); 从左至右O(m)枚举时,也可以使用栈来保存每一列连续颜色的高度,同时可以求周长的最大值,复杂度(n * m)。
 

1010

本题是一道简单的模拟题,关键点是看懂题目绕口的定义,然后按照题目所给的公式求解即可。实现过程可以使用map来判断检索出的url是否为相关文件,使用istringstream处理字符串操作。具体如何实现都行,总之本题考察读题和基本字符串处理。
 

1011

搜索+剪枝               
如果遇到已经100%的情况就直接break             
一开始可以不去考虑不会补充新的棋子的情况 如果有100%的情况 那也可以直接break了。
原文地址:https://www.cnblogs.com/pony1993/p/2617253.html