官方解题报告:http://blog.sina.com.cn/s/blog_6bddecdc0102v01l.html

A simple brute force problem. http://acm.hdu.edu.cn/showproblem.php?pid=4971

有n个项目,m个问题,解决某个项目会需要解决一些问题,解决项目挣钱,解决问题花钱,某些问题解决之前需解决其他问题。a之前要做b,b之前要做a,也就是会出现环,需要先缩点,参考有向图强连通分量缩点。对于缩点之后的图,参考最大权闭合图的方法建图,源点s到正权点,流量正权值,原图全连inf流量,负权点到汇点t连负权的绝对值。跑出来的最大流也是最小割,用所有正权减去最小割就是可获得的最大权值。

 #include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<queue>
#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;
const int M=;
const int inf=0x3f3f3f3f;
int val[M],cost[M],newcost[M];
vector<int> need[M];
class Tarjan{///有向图强连通分量缩点
static const int ME=M*M;///边的个数
static const int MV=M;///点的个数
int Index,Bcnt,num[MV],belong[MV],dfn[MV],low[MV];
bool instack[MV];
stack<int> s;
void tarjan(int u) {
dfn[u]=low[u]=++Index;
instack[u]=true;
s.push(u);
int v;
for(int i=g.head[u]; ~i; i=g.e[i].next) {
v=g.e[i].v;
if(!dfn[v]) {
tarjan(v);
low[u]=min(low[u],low[v]);
} else if(instack[v]) {
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]) {
Bcnt++;
do {
v=s.top();
s.pop();
instack[v]=false;
belong[v]=Bcnt;
num[Bcnt]++;
} while(u!=v);
}
}
public:
struct G {
struct E {
int u,v,next;
} e[ME];
int le,head[MV];
void init() {
le=;
mt(head,-);
}
void add(int u,int v) {
e[le].u=u;
e[le].v=v;
e[le].next=head[u];
head[u]=le++;
}
} g;
public:
void init() {
g.init();
Index=Bcnt=;
mt(num,);
mt(dfn,);
mt(low,);
mt(instack,);
while(!s.empty()) s.pop();
}
void add(int u,int v) {
g.add(u,v);
}
void solve(int n) {///传入点数,点下标1开始
for(int i=; i<=n; i++) {
if(!dfn[i]) {
tarjan(i);
}
}
}
int getbcnt() {///强连通分量的个数
return Bcnt;
}
int getbelong(int id) {///属于哪个分量,分量下标1开始
return belong[id];
}
int getnum(int id) {///某个分量的点的个数
return num[id];
}
}tarjan;
class Dinic { ///最大流 O(MV^2*ME)
typedef int typef;///流量的类型
static const int ME=M*M;///边的个数
static const int MV=M;///点的个数
int temp[MV],cur[MV],level[MV],path[MV];
bool used[MV];
queue<int> q;
typef flow;
bool bfs(int s,int t) {
mt(level,-);
while(!q.empty()) q.pop();
q.push(s);
level[s]=;
while(!q.empty()) {
int u=q.front();
q.pop();
for(int i=g.head[u]; ~i; i=g.e[i].next) {
int v=g.e[i].v;
if(level[v]==-&&g.e[i].flow) {
level[v]=level[u]+;
q.push(v);
if(v==t) return true;
}
}
}
return false;
}
struct G {
struct E {
int u,v,next;
typef flow;
} e[ME];
int le,head[MV];
void init() {
le=;
mt(head,-);
}
void add(int u,int v,typef flow) {
e[le].u=u;
e[le].v=v;
e[le].flow=flow;
e[le].next=head[u];
head[u]=le++;
}
} g;
public:
typef getflow() {
return flow;
}
void init() {
g.init();
}
void add(int u,int v,typef flow) {
g.add(u,v,flow);
g.add(v,u,);
}
void solve(int s,int t) {
int p,tempp;
typef now;
bool flag;
flow=;
while(bfs(s,t)) {
for(int i=; i<MV; i++) {
temp[i]=g.head[i];
used[i]=true;
}
p=;
path[p]=s;
while(p) {
int u=path[p];
if(u==t) {
now=inf;
for(int i=; i<p; i++) {
now=min(now,g.e[cur[path[i]]].flow);
}
flow+=now;
for(int i=; i<p; i++) {
int j=cur[path[i]];
g.e[j].flow-=now;
g.e[j^].flow+=now;
if(!g.e[j].flow) tempp=i;
}
p=tempp;
} else {
flag=false;
for(int i=temp[u]; ~i; i=g.e[i].next) {
int v=g.e[i].v;
if(used[v]&&g.e[i].flow&&level[u]+==level[v]) {
cur[u]=i;
temp[u]=g.e[i].next;
flag=true;
path[++p]=v;
break;
}
}
if(flag) continue;
p--;
used[u]=false;
}
}
}
}
} dinic;
int main(){
int t,n,m;
while(~scanf("%d",&t)){
for(int cas=;cas<=t;cas++){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
scanf("%d",&val[i]);
}
for(int i=;i<=m;i++){
scanf("%d",&cost[i]);
}
for(int i=,num,id;i<=n;i++){
scanf("%d",&num);
need[i].clear();
while(num--){
scanf("%d",&id);
need[i].push_back(id+);
}
}
tarjan.init();
for(int i=;i<=m;i++){
for(int j=,op;j<=m;j++){
scanf("%d",&op);
if(op){
tarjan.add(i,j);
}
}
}
tarjan.solve(m);
dinic.init();
for(int i=;i<tarjan.g.le;i++){
int u=tarjan.g.e[i].u;
int v=tarjan.g.e[i].v;
u=tarjan.getbelong(u);
v=tarjan.getbelong(v);
if(u!=v){
dinic.add(u+n,v+n,inf);
}
}
for(int i=;i<=n;i++){
int len=need[i].size();
for(int j=;j<len;j++){
dinic.add(i,n+tarjan.getbelong(need[i][j]),inf);
}
}
int s=,t=n+m+;
int sum=;
for(int i=;i<=n;i++){
dinic.add(s,i,val[i]);
sum+=val[i];
}
mt(newcost,);
for(int i=;i<=m;i++){
newcost[tarjan.getbelong(i)]+=cost[i];
}
for(int i=;i<=tarjan.getbcnt();i++){
dinic.add(i+n,t,newcost[i]);
}
dinic.solve(s,t);
printf("Case #%d: %d\n",cas,sum-dinic.getflow());
}
}
return ;
}

A simple water problem http://acm.hdu.edu.cn/showproblem.php?pid=4974

每次最多贡献2分,结果至少是最大值,偶数就sum/2,奇数还要加一。

 #include<cstdio>
#include<algorithm>
using namespace std;
typedef __int64 LL;
int main(){
int t,n,a;
while(~scanf("%d",&t)){
for(int cas=;cas<=t;cas++){
scanf("%d",&n);
int big=;
LL sum=;
while(n--){
scanf("%d",&a);
big=max(big,a);
sum+=a;
}
LL ans=sum/;
if(sum&) ans++;
printf("Case #%d: %I64d\n",cas,max((LL)big,ans));
}
}
return ;
}

A simple probability problem. http://acm.hdu.edu.cn/showproblem.php?pid=4978

这种做法比较好理解。

题目说是有间距为D的等间距的无穷条平行线,考虑一个线段长度为L的概率。题目说点在直径为D的圆内,所以L<=D.

平行时除了一次重合,别的都没有相交,概率约等于0.垂直的概率就是L/D。考虑通用情况,设平行线与我们的线段L夹角为θ。

则要转化成垂直然后计算概率,那么就是长度Lsinθ在D之间的概率。综上所述,对任意夹角θ,有通用公式概率P=L*sin(θ)/D.经检验,0度90度满足公式。

因为是随机放球,相当于夹角θ是随机的,L,D都是定值,那么概率就等于sin(θ)在0到180的均值。因为是随机,所以每个角度等概率,所以是均值。

为了计算sin(θ)的均值,打不出来了。考虑用面积,就是定积分来求。因为面积=定积分=底乘高,如果把函数图像拉直成一个矩形,面积就是y*(x2-x1)。

y就是均值,x1=0,x2=π。那个是派,3.1415926,是弧度中的180度.

求出来发现面积是2,也就是y*(pi-0)=2,那么sin(θ)的均值也就是y就等于2/pi. pi是派 3.14。

L*sin(θ)/D 等于下方结果。

所以官方题解的第一句话证毕。

现在我们的问题是圆内有n个点,他们之间两两间有线段,求和直线相交的概率。

通俗的想,里面的肯定没有外面的好,如果外面的相交的长度肯定大于里面的,这里就可以想到凸包。

然后就套凸包模板。然后点就只剩下凸包上的了。

然后就变成了求凸包和直线相交的概率=P。

接着,凸包要和直线相交,那么必然有凸包上的两条边和直线相交了。因为直线穿过了这个凸包,如果只和一条边相交,那就重合,是边界条件,对概率影响几乎为零,不考虑。

紧接着,凸包和直线相交,不可能穿过3条边,或者更多,因为是凸包。所以我们得到一个朴素的结论,凸包和直线相交的情况,就是有且仅有2条边与直线相交。

定义P i 表示 第i 条边和直线相交的概率。

则我们所求的凸包和直线相交的概率就是 P=1/2* sum(Pi) (i=1,2,...n) 其中pi 是线段 i 与直线相交的概率。我们把所有凸包的边枚举了,把他们的概率加起来。

之所以要除以2,因为一条直线一定会穿过两条边,那么对每一条直线,我们在概率里都算了两次,所以求和后除以2.

P=1/2* sum(Pi) (i=1,2,...n)

记@=3.1415926
我们刚才推出了一条边的概率  Pi =2*Li/(@*D) . 带入上式

P=(1/2)  *  sum (  2*Li  /  ( @ *D )    )  (i=1,2,...n)

除了Li 其他都可以提出来

P = (1/  ( @ * D ) )  * sum( Li )  (i=1,2,...n)

@是派,实在难打,好了  sum Li  不就是周长吗。

 #include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double pi=acos(-1.0);
const double eps=1e-;
const int M=;
struct point{
double x,y;
}p[M],res[M];
bool operator < (const point &l, const point &r) {
return l.y < r.y || (fabs(l.y- r.y)<eps && l.x < r.x);
}
class ConvexHull { //凸包
bool mult(point sp, point ep, point op) {//>包括凸包边上的点,>=不包括
return (sp.x - op.x) * (ep.y - op.y)>= (ep.x - op.x) * (sp.y - op.y);
}
public:
int graham(int n,point p[],point res[]) {//多边形点个数和点数组,凸包存res
sort(p, p + n);
if (n == ) return ;
res[] = p[];
if (n == ) return ;
res[] = p[];
if (n == ) return ;
res[] = p[];
int top=;
for (int i = ; i < n; i++) {
while (top && mult(p[i], res[top], res[top-])) top--;
res[++top] = p[i];
}
int len = top;
res[++top] = p[n - ];
for (int i = n - ; i >= ; i--) {
while (top!=len && mult(p[i], res[top],res[top-])) top--;
res[++top] = p[i];
}
return top; // 返回凸包中点的个数
}
} gx;
double Distance(point p1,point p2) {
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
int main(){
int t,n,d;
while(~scanf("%d",&t)){
for(int cas=;cas<=t;cas++){
scanf("%d%d",&n,&d);
for(int i=;i<n;i++){
scanf("%lf%lf",&p[i].x,&p[i].y);
}
int lr=gx.graham(n,p,res);
res[lr]=res[];
double sum=;
for(int i=;i<lr;i++){
sum+=Distance(res[i],res[i+]);
}
printf("Case #%d: %.4f\n",cas,sum/pi/d);
}
}
return ;
}

其实我是想说,这种做法比较好理解,虽然不是正解,但只要精度够了,也能过。

上面说过,一条线,长度L,那么概率是 通用公式P=L*sin(θ)/D.  角度是0到180,等可能,而对于凸包,某一个角度和直线相交的概率就是这个角度下凸包最远距离。

如图,在某一个角度θ下,与直线相交的概率就是凸包在与直线垂直的方向上的投影。maxL。  为了求这个投影,可以on的枚举凸包的点,计算到直线的最近距离的点。

然后因为这些点在直线上是递增的。所以取最大的和最小的,就是最远的两个点。然后就可以算出maxl, maxl/D就是当前角度下的概率,我们自定义个增量枚举角度。

对每一个角度都求一个maxl,  最后  sum(maxLi)/num 就是平均长度,  再/D就是概率。

 #include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double pi=acos(-1.0);
const double eps=1e-;
const int M=;
struct point {
double x,y;
} p[M],res[M];
bool operator < (const point &l, const point &r) {
return l.y < r.y || (fabs(l.y- r.y)<eps && l.x < r.x);
}
class ConvexHull { //凸包
bool mult(point sp, point ep, point op) {//>包括凸包边上的点,>=不包括
return (sp.x - op.x) * (ep.y - op.y)>= (ep.x - op.x) * (sp.y - op.y);
}
public:
int graham(int n,point p[],point res[]) {//多边形点个数和点数组,凸包存res
sort(p, p + n);
if (n == ) return ;
res[] = p[];
if (n == ) return ;
res[] = p[];
if (n == ) return ;
res[] = p[];
int top=;
for (int i = ; i < n; i++) {
while (top && mult(p[i], res[top], res[top-])) top--;
res[++top] = p[i];
}
int len = top;
res[++top] = p[n - ];
for (int i = n - ; i >= ; i--) {
while (top!=len && mult(p[i], res[top],res[top-])) top--;
res[++top] = p[i];
}
return top; // 返回凸包中点的个数
}
} tubao;
double xmult(point p1,point p2,point p0) {
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
double Distance(point p1,point p2) {
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
struct line {
point a,b;
};
point intersection(point u1,point u2,point v1,point v2) {
point ret=u1;
double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x)) /((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));
ret.x+=(u2.x-u1.x)*t;
ret.y+=(u2.y-u1.y)*t;
return ret;
}
point ptoline(point p,line l) {//点到直线上的最近点
point t=p;
t.x+=l.a.y-l.b.y,t.y+=l.b.x-l.a.x;
return intersection(p,t,l.a,l.b);
}
int main() {
int t,n;
double D;
while(~scanf("%d",&t)) {
int cas=;
while(t--) {
scanf("%d%lf",&n,&D);
for(int i=; i<n; i++) {
scanf("%lf%lf",&p[i].x,&p[i].y);
}
int lr=tubao.graham(n,p,res);
double sum=;
int num=;
double add=180.0/;
for(double jiao=; jiao<; jiao+=add) {
double xita=jiao/*pi;
line ll;
ll.a.x=ll.a.y=;
ll.b.x=;
ll.b.y=tan(xita);
point p1=ptoline(res[],ll);
point p2=p1;
for(int i=; i<lr; i++) {
point p3=ptoline(res[i],ll);
p1=max(p1,p3);
p2=min(p2,p3);
}
sum+=Distance(p1,p2);
num++;
}
printf("Case #%d: %.4f\n",cas++,sum/D/num);
}
}
return ;
}

end

2014 Multi-University Training Contest 10的更多相关文章

  1. 2016 Multi-University Training Contest 10

    solved 7/11 2016 Multi-University Training Contest 10 题解链接 分类讨论 1001 Median(BH) 题意: 有长度为n排好序的序列,给两段子 ...

  2. hdu 5416 CRB and Tree(2015 Multi-University Training Contest 10)

    CRB and Tree                                                             Time Limit: 8000/4000 MS (J ...

  3. 2015 Multi-University Training Contest 10 hdu 5406 CRB and Apple

    CRB and Apple Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...

  4. 2015 Multi-University Training Contest 10 hdu 5412 CRB and Queries

    CRB and Queries Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Other ...

  5. [二分,multiset] 2019 Multi-University Training Contest 10 Welcome Party

    Welcome Party Time Limit: 4000/4000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)T ...

  6. 2015 Multi-University Training Contest 10(9/11)

    2015 Multi-University Training Contest 10 5406 CRB and Apple 1.排序之后费用流 spfa用stack才能过 //#pragma GCC o ...

  7. 2016 Multi-University Training Contest 10 || hdu 5860 Death Sequence(递推+单线约瑟夫问题)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5860 题目大意:给你n个人排成一列编号,每次杀第一个人第i×k+1个人一直杀到没的杀.然后 ...

  8. 2015 Multi-University Training Contest 10 hdu 5407 CRB and Candies

    CRB and Candies Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...

  9. 2015 Multi-University Training Contest 10 hdu 5411 CRB and Puzzle

    CRB and Puzzle Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...

随机推荐

  1. 实例介绍Cocos2d-x开关菜单

    开关菜单是MenuItemToggle类实现的,它是一种可以进行两种状态切换的菜单.它可以通过下面的函数创建: static MenuItemToggle*createWithCallback  ( ...

  2. (转)RabbitMQ消息队列(五):Routing 消息路由

    上篇文章中,我们构建了一个简单的日志系统.接下来,我们将丰富它:能够使用不同的severity来监听不同等级的log.比如我们希望只有error的log才保存到磁盘上. 1. Bindings绑定 上 ...

  3. JavaScript知识思维导图

    知识点:(图片为网络转载,谢谢分享.) JavaScript 变量 JavaScript 数据类型 JavaScript 字符串函数 Javascript 运算符 JavaScript 流程控制 Ja ...

  4. 'hibernate.dialect' must be set when no Connection avalable

    'hibernate.dialect' must be set when no Connection avalable 当连接不可用时,必须要设置Hibernate方言 搜索大多数的解决办法是:首先查 ...

  5. AOJ 2200 Mr. Rito Post Office

    Mr. Rito Post Office Time Limit : 8 sec, Memory Limit : 65536 KB Problem D: Mr. Rito Post Office あなた ...

  6. Qt学习总结-ui篇

    控件设置透明度: QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(this); effect->setOpacity(0. ...

  7. sublime3 注册码

    —– BEGIN LICENSE —– Michael Barnes Single User License EA7E-821385 8A353C41 872A0D5C DF9B2950 AFF6F6 ...

  8. pipe/popen/fifo

    pipe(管道) 专用于父子进程通信, 函数原型 int pipe(int fd[2]) fd[0]表示输入, fd[1]表示输出 如果父子进程要双向通信, 可以通过类似信号的功能进行控制, 也可以简 ...

  9. Hive基本命令整理

    创建表: hive> CREATE TABLE pokes (foo INT, bar STRING);          Creates a table called pokes with t ...

  10. swap分区添加

    首先你需要使用命令:dd 来创建一个swapfile,然后你需要使用mkswap命令在设备或者文件中创建一个Linux swap分区a) 使用root用户登陆b) 使用下面的命令创建一个2G的 Swa ...