The 2013 ACMICPC Asia Regional Chengdu
还有19天出发北京站,今年北京站的出题方是上交,去年他们出的成都现场的赛题,首先复盘一下。
去年的成都是我经历的第一次现场赛,也是近距离第一次见到了CLJ的真人,最后也是被虐惨了,那时候是声闻大神带着我们去的,也是在那次现场之后,深深地感受到了差距。现在我们进步了,只可惜选手都在发展,比赛也在发展,别人大概是进步得更多吧,上场西安赛站也只能遗憾。
没想到最后一场居然又能碰到开场第一次能够遇上的出题方,也是个奇妙的巧合吧。
【B】模拟
【C】-_-///
【E】计算几何
【G】在线AC自动机
【I】模拟(用STL中的set)
----------------------------------------------------
【A】 HDU 4781
Assignment For Princess
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Special Judge
【Sample Output】
Case #:
【Hint】
The restrictions like N >= 10 will be too big for a sample. So the sample is just a simple case for the detailed formats of input and output,
and it may be helpful for a better understanding. Anyway it won’t appear in actual test cases.
/* ***********************************************
MYID : Chen Fan
LANG : G++
PROG : HDU 4781
************************************************ */ #include <iostream>
#include <cstdio>
#include <cstring> using namespace std; int mapl[][],dist[][];
bool use[]; int main()
{
int t,n,m;
scanf("%d",&t);
for (int tt=;tt<=t;tt++)
{
printf("Case #%d:\n",tt);
scanf("%d%d",&n,&m);
int tot=;
bool bq=false;
memset(mapl,,sizeof(mapl));
memset(dist,-,sizeof(dist)); for (int i=;i<n;i++)
{
tot+=i;
mapl[i][i+]=i;
dist[i][i+]=i;
} for (int i=n;i<n+;i++)
if ((tot+i)%==)
{
mapl[n][]=i;
dist[n][]=i;
break;
} memset(use,,sizeof(use));
use[mapl[n][]]=true; for (int i=;i<=n;i++)
for (int j=;j<=n;j++)
if (i!=j)
for (int k=;k<=n;k++)
if (i!=k&&j!=k)
if (dist[j][i]>&&dist[i][k]>)
if (dist[j][k]==-) dist[j][k]=dist[j][i]+dist[i][k]; for (int i=;i<=n;i++)
for (int j=;j<=n;j++)
if (dist[i][j]>-) dist[i][j]%=; //for (int i=1;i<=n;i++)
//for (int j=1;j<=n;j++) printf("%d %d %d\n",i,j,dist[i][j]); for (int i=n;i<=m;i++)
{
if (!use[i])
{
for (int j=;j<=n;j++)
for (int k=;k<=n;k++)
if (!use[i])
if (mapl[j][k]==&&mapl[k][j]==&&dist[j][k]>-&&dist[j][k]%==i%)
{
mapl[j][k]=i;
use[i]=true;
}
}
if (!use[i])
{
printf("-1\n");
bq=true;
break;
}
} if (!bq)
for (int i=;i<=n;i++)
for (int j=;j<=n;j++)
if (mapl[i][j]>) printf("%d %d %d\n",i,j,mapl[i][j]);
} return ;
}
Dinner Coming Soon
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Others)
- -
- - - -
- -
【Sample Output】
Case #:
Case #: Forever Alone
【题意】
给出一张有向图,主人公需要在时间T之内从编号为1的点走到编号为n的点。图中存在一个货币系统,主人公在初始状态的时候身上有R单位的货币,在图中除了1和n之外的所有点都可以买进或者卖出一包盐,每一个点的盐价不同,因此主人公可以通过这种方式在不同的位置进行盐的买卖赚取收益。图中的每一条有向边都有两个代价,时间花费和货币花费,而且除此之外这张图中还有K个“平行世界”,分别标记为0~K-1,在每个不同的平行世界中每个点的盐价也不同,主人公可以花费1单位时间从第i个平行世界的某个点中跳跃到第(i+1)%K个平行世界的同一个点上,唯一的限制是1点和n点只能从第0个平行世界中进入,且一旦到达第n点,这次遍历就结束了。
现在,最终的问题就是主人公从1点出发走到n点,身上最多可能持有多少单位的货币。
【分析】
写这道题的时候代码遭遇神坑啊!!!!
首先构图非常简单,相对于一般的图,本题只是把普通的单一代价有向边再加上一个代价,平行世界的跳转只是从i跳到(i+1)%k,且花费只有1单位时间。对于图中每一个点的情况,很容易能够想到状态转移方程式,用f(i,j,k,l)表示当前在第i点,花费了j时间,手上持有k包盐,目前在平行世界k的最大持有货币数。出现的位置状态转移只有两种:沿着有向边走向下一个点或者进行平行世界跳转。位置转移完成之后,接下来发生的价值转移有三种,不作任何操作、买入一包盐或者卖出一包盐。大致的方程是这样的,这里省略了一些转移条件:
f(i,j,k,l)=max{ f(p,j+edge[i,p].time,k,l),
f(p,j+edge[i,p].time,k+1,l)-price[l][p],
f(p,j+edge[i,p].time,k-1,l)+price[l][p],
f(i,j+1,k,(l+1)%K),
f(i,j+1,k+1,(l+1)%K)-price[(l+1)%K][i],
f(i,j+1,k-1,(l+1)%K)+price[(l+1)%K][i] }
最直接的想法是使用SPFA作为整体的DP框架,虽然整体数据范围不太大,但是这里反复进出队列的话,超时的可能性非常大。这里DP遇到的最大问题是后效性,关于这一点,我们可以看到状态递推的方向是花费时间增加的方向。普通的SPFA不能保证后面加入队列的状态时间一定是递增的,因此需要反复多次进出队列,所以在这里使用一个花费时间递增的优先队列来替换掉SPFA中的普通队列,保证状态按照花费时间递增的顺序来扩展,就能解决DP的后效性问题,记录一下加入过队列的点不用再次加入即可节省下来大量的时间。
写代码的时候因为一点失误被坑了好久......吸取的教训是:DP中后续的六种状态的值必须从原始状态出发!其实这个原本是非常直观的,写到图论的结构里面之后因为代码太多了,居然简单地就直接从1往2、3写,从4往5、6写了。
/* ***********************************************
MYID : Chen Fan
LANG : G++
PROG : HDU4784
************************************************ */ #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue> using namespace std; typedef struct nod{
int a,b,c,d;
} node; int start[],num[];
int p[][];
int n,m,b,k,r,tim;
node edge[]; typedef struct qnod
{
int s,t,b,k;
friend bool operator < (qnod a,qnod b)
{
return a.t>b.t;
}
} qnode; int f[][][][]; bool op(node a,node b)
{
return a.a<b.a;
} int main()
{
freopen("test.txt","r",stdin); int t;
scanf("%d",&t);
for (int tt=;tt<=t;tt++)
{
scanf("%d%d%d%d%d%d",&n,&m,&b,&k,&r,&tim);
for (int i=;i<k;i++)
for (int j=;j<=n;j++) scanf("%d",&p[i][j]);
for (int i=;i<=m;i++) scanf("%d%d%d%d",&edge[i].a,&edge[i].b,&edge[i].c,&edge[i].d);
sort(&edge[],&edge[m+],op); int o=;
memset(num,,sizeof(num));
for (int i=;i<=m;i++)
{
if (o!=edge[i].a)
{
o=edge[i].a;
start[o]=i;
}
num[o]++;
} printf("Case #%d: ",tt); priority_queue<qnode> q;
while (!q.empty()) q.pop();
memset(f,-,sizeof(f)); qnode st;
st.s=;st.t=;st.b=;st.k=;
f[][][][]=r;
q.push(st); int ans=-;
while (!q.empty())
{
qnode now=q.top();
q.pop(); for (int i=;i<num[now.s];i++)
{
qnode next;
int mm=f[now.s][now.t][now.b][now.k]-edge[start[now.s]+i].d;
next.t=now.t+edge[start[now.s]+i].c;
if (mm<||next.t>tim) continue;
next.s=edge[start[now.s]+i].b;
next.b=now.b;
next.k=now.k; if (next.s==&&next.k!=) continue;
if (next.s==n)
{
if (next.k!=) continue;
if (ans<mm) ans=mm;
} else
{
if (f[next.s][next.t][next.b][next.k]<) q.push(next);
if (f[next.s][next.t][next.b][next.k]<mm) f[next.s][next.t][next.b][next.k]=mm; if (next.s==) continue;
if (next.b<b&&f[next.s][next.t][next.b][next.k]>=p[next.k][next.s])
{
qnode temp=next;
temp.b++;
mm=f[now.s][now.t][now.b][now.k]-edge[start[now.s]+i].d-p[next.k][next.s]; //!!!!!
if (f[temp.s][temp.t][temp.b][temp.k]<) q.push(temp);
if (f[temp.s][temp.t][temp.b][temp.k]<mm) f[temp.s][temp.t][temp.b][temp.k]=mm;
} if (next.b>)
{
qnode temp=next;
temp.b--;
mm=f[now.s][now.t][now.b][now.k]-edge[start[now.s]+i].d+p[next.k][next.s];
if (f[temp.s][temp.t][temp.b][temp.k]<) q.push(temp);
if (f[temp.s][temp.t][temp.b][temp.k]<mm) f[temp.s][temp.t][temp.b][temp.k]=mm;
}
}
}
if (now.s==) continue;
qnode next=now;
int mm=f[now.s][now.t][now.b][now.k];
next.k=(next.k+)%k;
next.t++;
if (next.t>tim) continue; if (f[next.s][next.t][next.b][next.k]<) q.push(next);
if (f[next.s][next.t][next.b][next.k]<mm) f[next.s][next.t][next.b][next.k]=mm; if (next.b<b&&f[next.s][next.t][next.b][next.k]>=p[next.k][next.s])
{
qnode temp=next;
temp.b++;
mm=f[now.s][now.t][now.b][now.k]-p[next.k][next.s];
if (f[temp.s][temp.t][temp.b][temp.k]<) q.push(temp);
if (f[temp.s][temp.t][temp.b][temp.k]<mm) f[temp.s][temp.t][temp.b][temp.k]=mm;
} if (next.b>)
{
qnode temp=next;
temp.b--;
mm=f[now.s][now.t][now.b][now.k]+p[next.k][next.s];
if (f[temp.s][temp.t][temp.b][temp.k]<) q.push(temp);
if (f[temp.s][temp.t][temp.b][temp.k]<mm) f[temp.s][temp.t][temp.b][temp.k]=mm;
}
} if (ans<) printf("Forever Alone\n");
else printf("%d\n",ans);
} return ;
}
【F】 HDU 4786
Fibonacci Tree
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
【Sample Output】
Case #: Yes
Case #: No
【题意】
给出一张无向图,图中每一条边都有黑或者白两种颜色。询问是否可以从这张图中找到这样一个生成树,使得白边的条数为一个斐波那契数。
【分析】
考虑使用Kruskal构造最小生成树的方法,如果把颜色作为边权值,则可以构造出白边优先或者黑边优先的生成树。
白边优先树是尽可能多的取白边,能得到最多的使生成树成立的白边数,黑边优先树则是尽可能多的取黑边,得到最少的使生成树成立的白边数。从白边优先树出发的话,如果我们取掉一条白边,添加一条黑边,则构成的新图一定还是一棵树。即根据这个原理,可以构造出白边数介于最少白边数和最大白边数之间的所有生成树。接下来只要判断一下介于这两个数之间是不是存在斐波那契数即可。
/* ***********************************************
MYID : Chen Fan
LANG : G++
PROG : HDU4786
************************************************ */ #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bitset> typedef struct nod
{
int a,b,color;
} node; node edge[]; using namespace std; bool op(node a,node b)
{
return a.color<b.color;
} int n,m; int father[]; int getfather(int x)
{
if (father[x]!=x) father[x]=getfather(father[x]);
return father[x];
} void link(int x,int y)
{
father[getfather(x)]=getfather(y);
} int kruskal1()
{
for (int i=;i<=n;i++) father[i]=i;
int num=,tot=;
for (int i=;i<=m;i++)
if (getfather(edge[i].a)!=getfather(edge[i].b))
{
link(edge[i].a,edge[i].b);
if (edge[i].color) num++;
tot++;
}
if (tot!=n-) return -;
else return num;
} int kruskal2()
{
for (int i=;i<=n;i++) father[i]=i;
int num=,tot=;
for (int i=m;i>=;i--)
if (getfather(edge[i].a)!=getfather(edge[i].b))
{
link(edge[i].a,edge[i].b);
if (edge[i].color) num++;
tot++;
}
if (tot!=n-) return -;
else return num;
} int main()
{
int tot=;
bitset<>fbn;
fbn.reset();
int a=,b=,c;
fbn[]=;
while ()
{
c=a+b;
if (c>=) break;
fbn[c]=;
a=b;
b=c;
} int t;
scanf("%d",&t);
for (int tt=;tt<=t;tt++)
{
scanf("%d%d",&n,&m); for (int i=;i<=m;i++) scanf("%d%d%d",&edge[i].a,&edge[i].b,&edge[i].color); printf("Case #%d: ",tt); sort(&edge[],&edge[m+],op);
int b1=kruskal1(); if (b1<)
{
printf("No\n");
continue;
} int b2=kruskal2(); bool done=false;
for (int i=b1;i<=b2;i++)
if (fbn[i])
{
done=true;
break;
} if (done) printf("Yes\n");
else printf("No\n");
} return ;
}
【H】 HDU 4788
Hard Disk Drive
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
[MB]
[B]
【Sample Output】
Case #: 4.63%
Case #: 0.00%
【Hint】
【分析】
签到题
【J】 HDU 4790
Just Random
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
【Sample Output】
Case #: /
Case #: /
Case #: /
Case #: /
【题意】
给定两个区间,每次分别从这两个区间中取出一个数求和,问有多少种组合的和是能够对p取模之后等于m的概率。
【分析】
The 2013 ACMICPC Asia Regional Chengdu的更多相关文章
- HDU 4291 A Short problem(2012 ACM/ICPC Asia Regional Chengdu Online)
HDU 4291 A Short problem(2012 ACM/ICPC Asia Regional Chengdu Online) 题目链接http://acm.hdu.edu.cn/showp ...
- 2013 ACM/ICPC Asia Regional Chengdu Online 1004 Minimum palindrome
Minimum palindrome Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- The 2013 ACM-ICPC Asia Changsha Regional Contest - K
Pocket Cube Time Limit: 2 Seconds Memory Limit: 65536 KB Pocket Cube is a 3-D combination puzzl ...
- The 2013 ACM-ICPC Asia Changsha Regional Contest - J
Josephina and RPG Time Limit: 2 Seconds Memory Limit: 65536 KB Special Judge A role-playin ...
- The 2013 ACM-ICPC Asia Changsha Regional Contest - A
Alice's Print Service Time Limit: 2 Seconds Memory Limit: 65536 KB Alice is providing print ser ...
- 2013 ACM/ICPC Asia Regional Chengdu Online---1003
哈哈哈 #include <iostream> #include <cstring> #include <string> #include <cstdio&g ...
- 2013 ACM/ICPC Asia Regional Chengdu Online hdu4731 Minimum palindrome
Minimum palindrome Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- HDU4734——2013 ACM/ICPC Asia Regional Chengdu Online
今天做的比赛,和队友都有轻微被虐的赶脚. 诶,我做的题就是这个题目了. 题目描述就是对于一个十进制数数位上的每一位当做一个二进制位来求出这个数,这个定义为G(x). 题目给定你A和B,求在0-B范围内 ...
- HDU 4729 An Easy Problem for Elfness(主席树)(2013 ACM/ICPC Asia Regional Chengdu Online)
Problem Description Pfctgeorge is totally a tall rich and handsome guy. He plans to build a huge wat ...
随机推荐
- js跨域访问,No ‘Access-Control-Allow-Origin‘ header is present on
在本地用ajax跨域访问请求时报错: XMLHttpRequest cannot loadhttp://www.zjblogs.com/. No 'Access-Control-Allow-Origi ...
- SSH自动断开连接的原因
方法一: 用putty/SecureCRT连续3分钟左右没有输入, 就自动断开, 然后必须重新登陆, 很麻烦. 在网上查了很多资料, 发现原因有多种, 环境变量TMOUT引起,ClientAliveC ...
- centos 6.5常见lib库安装
在CentOS安装软件的时候,可能缺少一部分支持库,而报错.这里首先安装系统常用的支持库.那么在安装的时候就会减少很多的错误的出现. # yum install -y gcc gdb strace g ...
- runtime——消息机制
本文授权转载,作者:Sindri的小巢(简书) 从异常说起 我们都知道,在iOS中存在这么一个通用类类型id,它可以用来表示任何对象的类型 —— 这意味着我们使用id类型的对象调用任何一个方法,编译器 ...
- [Eclispe] NDK内建include路径修改
[Eclispe] NDK内建include路径修改 编辑 jni/android.mk 中 LOCAL_C_INCLUDES 变量后,该变量值将被列入项目属性的内建include头文件包含路径,无法 ...
- Flexigrid的API
基本设定 width table的长度(default:auto) height table的宽度(default:200) striped 表格的线的表示(default:true) nov ...
- 异步加载AsyncTask
private void huodeshuju() { new AsyncTask<String, Void, String>() { @Overrid ...
- XListview的下拉刷新、上拉加载、用Pull解析XML
做之前需要导入XListview的文件,此是用第三方的xListview实现的,东西没写全.此是在Fragment中实现的 //--------------XListView的布局---------- ...
- 河南多校大一训练赛 D
题目链接:http://acm.hust.edu.cn/vjudge/contest/125004#problem/D 密码:acm Description If an integer is not ...
- CodeForces 678A Johny Likes Numbers
简单题. #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> ...