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 " );
}
}
#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();
}
#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();
}
其他题解题报告待更新。
Enter
backward paragraph