Chengdu Regional 2008[被虐爆了,留个记号]

被打爆了。唉。自己蒟蒻啊。
随手写几句。
A 暴力竟然可过,worst-case难道不是O(N^2)?
B splay,yy半天并查集无果
C 区间DP?柯神orz,1Y
D 扫描线,回头写,我觉得可以做
E 矩形交转化成了DP,我弱爆了,想了半天扫描线+线段树
F 神题吧?看得懂题,木有想法
G yy了半天费用流神马的,竟然是贪心,蒟蒻啊。
H 题都没看
I 最短路,建图真恶心
J orz claire_大神
K 神马?

A题
这题数据真奇葩,正着做TLE,倒着做109msAC。数据不够随机啊,我擦嘞。
n个物品m种资源,给出对应关系,每种物品已有每种资源多少,每种物品分别还需要每种资源多少,每种资源现有多少。且如果某种物品满足需求,则它所占用的资源全部释放给你。就问有没有方法满足所有需求。

就是暴力,最坏O(N^2)的暴力。
每次循环对于所有能够满足的物品进行标记,标记之后把资源释放;不断循环,直到全标记,或出现一次循环中没有办法标记的情况则break
判定是否全标记再输出就好。
我擦。虽然最多标记N次,但是最坏可是O(N^2)的循环啊,说明它这数据不够随机,只卡了正着做,没卡倒着做。。不过如果随机了,没准就均摊可过,然后正做倒做都卡不住了。
这要是真去现场赛,遇到这种题不就坑死爹了嘛。

附代码:
#include <iostream>
#include 
<cstdio>
#include 
<cstring>
using namespace std;
#define maxn 50005
int n,m;
int a[4][maxn],b[4][maxn];
int res[4];
bool vis[maxn];
int main()
{
    
while(scanf("%d %d",&n,&m) == 2)
    {
        fill(vis,vis 
+ n,0);
        
for(int i = 0;i < m;i++)
            
for(int j = 0;j < n;j++)
                scanf(
"%d",&a[i][j]);
        
for(int i = 0;i < m;i++)
            
for(int j = 0;j < n;j++)
                scanf(
"%d",&b[i][j]);
        
for(int i = 0;i < m;i++)
            scanf(
"%d",&res[i]);
        
int cnt = n;
        
bool mark = false;
        
while(1)
        {
            
for(int i = n-1;i >= 0;i--)
                
if(!vis[i])
                {
                    
bool fuck = true;
                    
for(int j = 0;j < m;j++)
                    {
                        
if(res[j] < b[j][i])
                        {
                            fuck 
= false;
                            
break;
                        }
                    }
                    
if(fuck)
                    {
                        
for(int j = 0;j < m;j++)
                            res[j] 
+= a[j][i];
                        cnt
--;
                        vis[i] 
= true;
                        mark 
= true;
                    }
                }
            
if(!mark || cnt == 0)
                
break;
            mark 
= false;
        }
        printf(
"%s\n",cnt==0?"Yes":"No");
    }
}

E题
我是蒟蒻啊。这题那么简单的DP竟然没看出来。
给你N个矩形,让你求其中任意N-1个矩形的交的面积的最大值。

X个矩形交可以O(X)求出,因为两个矩形的交还是矩形。
于是乎正着求一遍,可以得到正序任意个矩形的交;反序亦然。
然后再O(N)扫一遍,ans = max(ans, intersection(inorder(i-1),reorder(i+1)).square()) 求出每个拆掉之后的其他矩形的交的面积的最大值。
WA点两处,只有一个矩形输出0,因为初始化正序第一和逆序第一均为无穷大矩形,容易2掉;求面积时记得判矩形非法。
中间sb了,想半天扫描线和线段树,我能再2点么!!!
附代码:
#include <iostream>
#include <cstdio>
using namespace std;
#define maxn 100005
const int inf = 15000;
struct rec
{
int d,l,u,r;
rec(){}
rec(int _d,int _l,int _u,int _r):d(_d),l(_l),u(_u),r(_r){}
int sq()
{
return (u >= d && r >= l)?(u - d) * (r - l):0;
}
}in[maxn],re[maxn],a[maxn];
rec inter(rec a,rec b)
{
return rec(max(a.d,b.d),max(a.l,b.l),min(a.u,b.u),min(a.r,b.r));
}
void gao()
{
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i++)
scanf("%d %d %d %d",&a[i].d,&a[i].l,&a[i].u,&a[i].r);
if(n == 1)
{
puts("0");
return ;
}
re[n+1] = in[0] = rec(-inf,-inf,inf,inf);
for(int i = 1;i <= n;i++)
in[i] = inter(in[i-1],a[i]);
for(int i = n;i >= 1;i--)
re[i] = inter(re[i+1],a[i]);
int ans = 0;
for(int i = 1;i <= n;i++)
ans = max(ans,inter(in[i-1],re[i+1]).sq());
printf("%d\n",ans);
}
int main()
{
int t;
scanf("%d",&t);
for(int i = 0;i < t;i++)
gao();
}

I题
给你个地图(带比例尺的那种),可缩放,有四个分区。
给一对起止坐标,是放大八次之后的地图上的坐标。
给N个点,是实际坐标,标号为字符串。
给m条公交路线,每条路线最多k个点。
给出两个约束:如果起止点距离<=2000m,则可以直接走过去;如果公交车站离起止点的距离<=1000m,则该车站为起止点可达。
可以在任意公交车站换乘公交路线。
问从起点到终点的最小换乘次数;走过去就是走过去;去不了就打的。

繁琐的建图:
首先是起止点的还原,放大的地图还原回去,每次都是x、y除2,并且要加上对应选区的偏移量,最后再乘上比例尺。
然后是公交车站的读入,map映射字符串,记录离起止点距离。
公交路线的读入,把公交路线抽象成图中实际的点,若路线中有站起止点可达,则和起止点连边;公交路线之间若有交叠部分,则连边。
dijkstra即可,最后结果-1即为答案。复杂度O(nlogn+m^2*k^2+m^2)=O(m^2*k^2)。。。。恶心题。。。尤其是地图放大那块,想半天想不清楚,手跑样例又真心无力。

附代码:
#include <iostream>
#include 
<cstdio>
#include 
<cstring>
#include 
<cmath>
#include 
<map>
#define maxn 105
#include 
<string>
#define MAX 5005
using namespace std;
bool mac[maxn][maxn];
int d[maxn];
const double eps = 1e-8;
const int inf = 10000;
int sgn(double x)
{
    
return fabs(x) < eps?0:x < -eps?-1:1;
}
struct point
{
    
double x,y;
    point(){}
    point(
double a,double b):x(a),y(b){}
    point 
operator -(const point p)
    {
        
return point(x - p.x,y - p.y);
    }
    
double norm()
    {
        
return sqrt(x * x + y * y);
    }
}p[MAX];
char opt[20];
int n,m;
int rel[maxn][maxn];
double fuck[2][MAX];
bool vis[maxn];
void dij()
{
    d[
0= 0;
    memset(vis,
0,sizeof(vis));
    
for(int i = 0;i <= m+1;i++)
    {
        
int mmm = inf,mark = 0;
        
for(int j = 0;j <= m+1;j++)
        {
            
if(!vis[j] && mmm > d[j])
            {
                mark 
= j;
                mmm 
= d[j];
            }
        }
        vis[mark] 
= true;
        
for(int j = 0;j <= m + 1;j++)
            
if(!vis[j] && mac[mark][j] && d[j] > d[mark] + 1)
                d[j] 
= d[mark] + 1;
    }
}
void gao()
{
    
double a,b;
    map
<string,int> M;
    
for(int k = 0;k < 2;k++)
    {
        scanf(
" %s %lf %lf",opt,&a,&b);
        
for(int i = 7;i >= 0;i--)
        {
            a 
/= 2.0;
            b 
/= 2.0;
            
if(opt[i] == '1')
                b 
+= 10;
            
else if(opt[i] == '2')
                a 
+= 10;
            
else if(opt[i] == '3')
            {
                a 
+= 10;
                b 
+= 10;
            }
        }
        a 
*= 512.0;
        b 
*= 512.0;
        p[k] 
= point(a,b);
    }
    memset(mac,
0,sizeof(mac));
    scanf(
"%d",&n);
    n
++;
    
for(int i = 2;i <= n;i++)
    {
        
double a,b;
        scanf(
" %s %lf %lf",opt,&a,&b);
        M[
string(opt)] = i;
        p[i] 
= point(a,b);
        fuck[
0][i] = (p[0- p[i]).norm();
        fuck[
1][i] = (p[1- p[i]).norm();
    }
    scanf(
"%d",&m);
    
if(sgn((p[0- p[1]).norm() - 2000.0<= 0)
        mac[
0][m+1= true;
    
for(int i = 1;i <= m;i++)
    {
        scanf(
"%d",&rel[i][0]);
        
for(int j = 1;j <= rel[i][0];j++)
        {
            scanf(
" %s",opt);
            rel[i][j] 
= M[string(opt)];
            
if(sgn(fuck[0][rel[i][j]] - 1000.0<= 0)
                mac[
0][i] = mac[i][0= 1;
            
if(sgn(fuck[1][rel[i][j]] - 1000.0<= 0)
                mac[m
+1][i] = mac[i][m+1= 1;
        }
    }
    
if(mac[0][m+1])
        puts(
"walk there");
    
else
    {
        
for(int i = 1;i <= m;i++)
        {
            
for(int j = i + 1;j <= m;j++)
            {
                
bool mark = false;
                
for(int k = 1;k <= rel[i][0];k++)
                {
                    
for(int q = 1;q <= rel[j][0];q++)
                    {
                        
if(rel[i][k] == rel[j][q])
                        {
                            mac[i][j] 
= mac[j][i] = 1;
                            mark 
= true;
                            
break;
                        }
                    }
                    
if(mark)
                        
break;
                }
            }
        }
        fill(d,d 
+ m + 2,inf);
        dij();
        
if(d[m+1== inf)
            puts(
"take a taxi");
        
else
            printf(
"%d\n",d[m+1]-1);
    }
}
int main()
{
    
int t;
    scanf(
"%d",&t);
    
for(int i = 0;i < t;i++)
        gao();
}

其他题解题报告待更新。

posted on 2011-09-26 00:36 BUPT-[aswmtjdsj] @ Penalty 阅读(236) 评论(0)  编辑 收藏 引用 所属分类: HDU Solution Report


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2011年9月>
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

导航

统计

常用链接

留言簿(1)

随笔分类(150)

随笔档案(71)

搜索

积分与排名

最新评论

阅读排行榜

评论排行榜