[CFgym]2015-2016 ACM-ICPC Pacific Northwest Regional Contest小结

*感谢两位浙江大佬带我飞

贴下成绩

div2

image

div1

image

*div2不是我打的上个厕所就5/11了

 

比赛小结

A

【题目大意】

有n(n<=500)个机场,两两之间距离是g[i][j],每经停一个机场需要p[i]的时间维修

有m条线路,描述为出发机场s_i,终点机场t_i,出发时间f_i,求航空公司至少需要多少架飞机

每条航线必须直飞

但是转机的时候可以劲停多个机场

【题解】

首先一架飞机能在完成航线A后去飞航线B的条件很显然。就是t_A+f_{t_A,s_B}$\leq$f_B

f_{t_A,s_B}表示两点间最短路。那么我们可以用这个不等式把问题转化为最小路径覆盖问题

我想了下这个最短路用Floyd吧n^3我选择死亡时限是5s应该能过的

然后忧虑了一下我的dinic的常数,写了个匈牙利,但是之后有人和我讲dinic更快?

#include<map>
#include<stack>
#include<queue>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<complex>
#include<iostream>
#include<assert.h>
#include<algorithm>
using namespace std;
#define inf 1001001001
#define infll 1001001001001001001LL
#define FOR0(i,n) for(int (i)=0;(i)<(n);++(i))
#define ll long long
#define dbg(vari) cerr<<#vari<<" = "<<(vari)<<endl
#define gmax(a,b) (a)=max((a),(b))
#define gmin(a,b) (a)=min((a),(b))
#define ios0 ios_base::sync_with_stdio(0)
#define Ri register int
#define gc getchar()
#define il inline
#define FOR1(i,n) for(Ri (i)=1;(i)<=(n);++(i))
il int read(){
    bool f=true;
    Ri x=0;char ch;
    while(!isdigit(ch=gc))if(ch=='-')f=false;
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=gc;}
    return f?x:-x;
}
#define gi read()
int n,m,p[555],g[555][555],f[555][555];
struct edge{
    int to,next;
}e[555*555],s1[555],s2[555];
int cnt,last[666],match[666],vis[666];
void insert(int a,int b){
    e[++cnt]=(edge){b,last[a]};last[a]=cnt;
}
int hungary(int u){  
    vis[u]=1;  
    for(int i=last[u];i;i=e[i].next){  
        int y=e[i].to;  
        if(match[y]==-1){  
            match[y]=u;  
            return 1;  
        }  
    }  
    for(int i=last[u];i;i=e[i].next){  
        int y=e[i].to;  
        if(!vis[match[y]]&&hungary(match[y])){  
            match[y]=u;  
            return 1;  
        }  
    }  
    return 0;  
}  
int main(){
    n=gi;m=gi;
    FOR1(i,n)p[i]=gi;
    FOR1(i,n)FOR1(j,n){
        int T=gi;
        if(i^j)g[i][j]=T+p[j];
        else g[i][j]=T;
        f[i][j]=g[i][j];
    }
    //n^3 floyd 
    FOR1(k,n)FOR1(i,n)FOR1(j,n)gmin(f[i][j],f[i][k]+f[k][j]);
    FOR1(i,m){
        int a,b,c;
        a=gi;b=gi;c=gi;
        s1[i]=(edge){a,c};
        s2[i]=(edge){b,c+g[a][b]};
    }
    FOR1(i,m){
        match[i]=-1;
        FOR1(j,m)if(i^j){
            if(s2[i].next+f[s2[i].to][s1[j].to]<=s1[j].next)insert(i,j); 
        }
    } 
    int fyb=n;
    FOR1(i,m){
        memset(vis,0,sizeof(vis));
        if(hungary(i))--fyb;
    }
    printf("%d",fyb);
    return 0;
}

 

C

【题目大意】

有n个人,他们的评级是由上(upper)中(middle)下(lower)组成的

两个评级的高底是从最后一个开始比较到第一个,一个中文的世纪大难题

求出从高到低的排列顺序

【题解】分类并排序md这都什么鬼题目啊

#include<map>
#include<stack>
#include<queue>
#include<cstdio>
#include<string.h>
#include<vector>
#include<cstring>
#include<complex>
#include<iostream>
#include<assert.h>
#include<algorithm>
using namespace std;
#define inf 1001001001
#define infll 1001001001001001001LL
#define FOR0(i,n) for(int (i)=0;(i)<(n);++(i))
#define FOR1(i,n) for(int (i)=1;(i)<=(n);++(i))
#define ll long long
#define dbg(vari) cerr<<#vari<<" = "<<(vari)<<endl
#define gmax(a,b) (a)=max((a),(b))
#define gmin(a,b) (a)=min((a),(b))
#define ios0 ios_base::sync_with_stdio(0)
#define Ri register int
#define gc getchar()
#define il inline
il int read(){
    bool f=true;
    Ri x=0;char ch;
    while(!isdigit(ch=gc))if(ch=='-')f=false;
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=gc;}
    return f?x:-x;
}
#define gi read()
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
int n;  
struct data{  
    char name[299];  
    int b[50];  
    bool operator<(data B)const{  
        for(int i=1;i<=49;i++)
            if(b[i]!=B.b[i])    return b[i]>B.b[i];
        return strcmp(name,B.name)<0;  
    }  
}a[1010];  
int main(){
    n=gi; 
    FOR1(i,n){
        scanf("%s",a[i].name);a[i].name[strlen(a[i].name)-1]='\0';
        int p=0,temp[33];
        char str[33];
        while(scanf("%s",str),str[0]!='c'){
            if(str[0]=='u')temp[++p]=1;  
            if(str[0]=='m')temp[++p]=0;  
            if(str[0]=='l')temp[++p]=-1;  
        }
        int fyb=0;
        while(p)a[i].b[++fyb]=temp[p--];
    }
    sort(a+1,a+n+1);  
    FOR1(i,n)printf("%s\n",a[i].name);  
}

D

【题目大意】给定俩三角形问能不能拼成一个矩形

【题解】这你告诉我不会做回去种田吧

E

【题目大意】给定一个长度为偶数的能力值序列,要求两两分组,使得每组能力值的和的最小值最大

【题解】排序后贪心

G

【题目大意】给你一个w*h的矩形,w,h<=10^9。我们一开始在y=0的任一位置。开始移动当纵向速度是v,那么横向速度是[-v/r,v/r]之间,r是给定的小于等于10的正整数,给定10^5个点,问最多能抵达多少个点

【题解】

‎的题目

意给的是你移动的角度,考虑怎么转化这个东西

image(r=1时的合法角度范围

首先可以推算出来,r=cot^{-1}\theta

旋转这个坐标轴是最好的做法

我们把整个平面上的所有图形绕原点顺时针旋转某个度数。

举个例子,当r=1时,原来是(x,y)的坐标就变成(\frac{x+y}{\sqrt{2}},\frac{y-x}{\sqrt{2}})为方便计算把它乘\sqrt{2}得到(x+y,y-x)

image

由于角度在[C,B]之间的都是合法的

那么我们就把坐标轴旋转{\frac{180-2cot^{-1}r}{2}}^{\circ},这么做的目的是使得移动的影响同时反映在x,y上,而且可以计算

那么我们旋转这个度数之后,原有的(x,y),就变成了(-rx+y,rx+y)

所以我们只要对(-rx+y,rx+y)双关键字排序,第二维的LIS长度就是答案

言语有点混乱

如果哪里写错了请不要告诉我

#include<map>
#include<stack>
#include<queue>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<complex>
#include<iostream>
#include<assert.h>
#include<algorithm>
using namespace std;
#define inf 1001001001
#define infll 1001001001001001001ll
#define FOR0(i,n) for(int (i)=0;(i)<(n);++(i))
#define FOR1(i,n) for(int (i)=1;(i)<=(n);++(i))
#define ll long long
#define dbg(vari) cerr<<#vari<<" = "<<(vari)<<endl
#define gmax(a,b) (a)=max((a),(b))
#define gmin(a,b) (a)=min((a),(b))
#define ios0 ios_base::sync_with_stdio(0)
#define Ri register int
#define gc getchar()
#define il inline
il int read(){
    bool f=true;
    Ri x=0;char ch;
    while(!isdigit(ch=gc))if(ch=='-')f=false;
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=gc;}
    return f?x:-x;
}
il ll read2(){
    bool f=true;
    ll x=0;char ch;
    while(!isdigit(ch=gc))if(ch=='-')f=false;
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=gc;}
    return f?x:-x;
}
#define gi read()
#define gl read2()
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
const int N=100005;  
struct data{ll x,c;}a[N];  
int n,r,w,h;  
ll x,y;  
ll d[N];  
bool cmp(const data&a,const data&b){
    return a.c<b.c;
}
int main(){  
    n=gi;r=gi;w=gi;h=gi; 
    FOR1(i,n){
        ll x,y;
        x=gl;y=gl;
        a[i].c=r*x+y;
        a[i].x=-r*x+y;  
    }  
    sort(a+1,a+n+1,cmp);  
    d[0]=-infll;
    int len=0;  
    FOR1(i,n){  
        if(a[i].x>=d[len])d[++len]=a[i].x;  
        else d[lower_bound(d+1,d+len+1,a[i].x)-d]=a[i].x; 
    }  
    printf("%d\n",len);  
    return 0;  
}

比赛&题面链接

http://codeforces.com/gym/100820

http://codeforces.com/gym/100819

http://codeforces.com/gym/100820/attachments/download/3912/20152016-acmicpc-pacific-northwest-regional-contest-div-1-en.pdf

http://codeforces.com/gym/100819/attachments/download/3913/20152016-acmicpc-pacific-northwest-regional-contest-div-2-en.pdf

转载于:https://www.cnblogs.com/chouti/p/5742350.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值