比赛地址

Vjudge Contest

[A]Alice's Print Service

题意

打印一定的页数的文件会产生一些费用,每页的打印代价是一个分段函数,当总页数达到一定值得时候,每页的费用会发生变化.给出计费策略和需要打印的总页数,求最小花费.

题解

签到题

代码

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
using namespace std;

int T, n, m;
long long int s[100005], p[100005], used[100005], a;

int main(){
    cin >> T;
    while(T--) {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            scanf("%lld%lld", &s[i], &p[i]);
        }
        for (int i = 1; i <= n; i++) used[i] = s[i] * p[i];
        for (int i = n-1; i >= 1; i--) used[i] = min(used[i], used[i+1]);
        used[n+1] = used[n];
        for (int i = 1; i <= m; i++) {
            scanf("%lld", &a);
            int x = 1, y = n;
            while(y > x) {
                int mid = ((x+y) >> 1) + 1;
                if (a >= s[mid]) x = mid;
                else y = mid - 1;
            }
            if (x == n) cout << a*p[x] << endl; 
            else    cout << min(a*p[x], used[x+1]) << endl;
        }
    }
    return 0;
}

[C]Collision

题意

在桌面的圆形轨道区域内部有一个光滑的圆形障碍,现在在桌面上滑出一枚硬币,给出硬币的速度矢量和半径大小,求硬币的某一部分在轨道内部的总时间.

题解

计算几何

代码

#include <cstdio>
#include <cmath>
#include <cstring>
#include <climits>
#include <cctype>
#include <cfloat>
#include <vector>
#include <algorithm>

#define GC getchar()
#define _Q_(x) {register char _c=GC,_v=1;for(x=0;_c<48||_c>57;_c=GC)if(_c==45)_v=-1;
#define _H_(x) for(;_c>=48&&_c<=57;x=(x<<1)+(x<<3)+_c-48,_c=GC);if(_v==-1)x=-x;}
#define sc(x) _Q_(x)_H_(x)
#define se(x) _Q_(x)else if(_c==EOF)return 0;_H_(x)

#define sqrt(x) sqrt(ABS(x))       //【极其重要】防止一个绝对值小于EPS的负数进入sqrt!!!! 类似的还有ac、as,要防止一个值为1+EPS or -1-EPS的数进入!!!! 
#define IL inline
#define OP operator


typedef double vint;

const vint EPS = 1e-6, INF = 1e22, PI = 3.141592653589793238462643383279502884197169399375105820974944592, RAD = 180 / PI;

enum PSTA
{
    REV_EX = -3, EX = 3,    // 反向延长线上,延长线上 
    IS_S = -2, IS_T = 2,    // 是起点,是终点
    RIGHT = -1, LEFT = 1,   // 在右侧(顺时针侧),在左侧(逆时针侧) 
    INSIDE = 0,             // 严格在内部

    N_SSSTA = 7,
    N_LSSTA = 3,
};

IL vint ABS(vint x) {return x>0 ? (x>EPS ? x:0) : (x<-EPS ? -x:0);}
IL vint MIN(vint a, vint b) {return a<b ? a:b;}
IL vint MAX(vint a, vint b) {return a>b ? a:b;}
IL bool eq(vint a, vint b) {return a>b ? a-b<EPS : b-a<EPS;}
IL bool zero(vint x) {return x>0 ? x<EPS : x>-EPS;}
IL int  sign(vint x) {return x>0 ? (x>EPS ? 1:0) : (x<-EPS ? -1:0);}
IL vint norm(vint x) {return x>0 ? (x>EPS ? x+EPS:0) : (x<-EPS ? x-EPS:0);}
#define PC putchar
void PRT(const char *fmt, vint x)   // 格式字串fmt后面加什么都行,但是务必保证开头第一个字符就是数字的第一位或者负号
{
    static char buf[666];
    sprintf(buf, fmt, norm(x));

    bool all_0 = true;
    for (char *p=buf; *p; ++p)
        if (isdigit(*p) && *p!='0')
        {
            all_0 = false;
            break;
        }
    printf("%s", buf + (all_0 && *buf=='-'));
}

IL vint sqr(vint x) {return x*x;}
IL vint cub(vint x) {return x*x*x;}
IL vint dtoa(vint d) {return d / RAD;}
IL vint atod(vint a) {return a * RAD;}

typedef struct Po
{
    vint x, y;

    Po(void) { }
    Po(vint xx, vint yy) : x(xx), y(yy) { }
    Po(const Po &a, const Po &b) : x(b.x-a.x), y(b.y-a.y) { }

    void println() const {PC('('), PRT("%.3f, ", x), PRT("%.3f)\n", y);}
    vint len() const {return sqrt(sqr(x) + sqr(y));}

    Po OP +(vint d) const {return Po(x+d, y+d);}
    Po OP -(vint d) const {return Po(x-d, y-d);}
    Po OP +=(vint d) {x+=d, y+=d; return *this;}
    Po OP -=(vint d) {x-=d, y-=d; return *this;}
    Po OP *(vint k) const {return Po(x*k, y*k);}
    friend Po OP*(vint k, const Po &o) {return Po(k*o.x, k*o.y);}
    Po OP /(vint k) const {return Po(x/k, y/k);}

    Po OP +(const Po &o) const {return Po(x+o.x, y+o.y);}
    Po OP -(const Po &o) const {return Po(x-o.x, y-o.y);}
    Po OP +=(const Po &o) {x+=o.x, y+=o.y; return *this;}
    Po OP -=(const Po &o) {x-=o.x, y-=o.y; return *this;}

    vint OP *(const Po &o) const {return x*o.x + y*o.y;}
    vint OP ^(const Po &o) const {return x*o.y - y*o.x;}
    vint OP |(const Po &o) const {return sqrt(sqr(x-o.x)+ sqr(y-o.y));}
} Vec;
vint dist(const Po &a, const Po &b)
{
    return sqrt(sqr(a.x-b.x) + sqr(a.y-b.y));
}

struct Li
{
    Po s, t;

    Li(void) { }
    Li(const Po &a, const Po &b) : s(a), t(b) { }
    Li(vint x1, vint y1, vint x2, vint y2) : s(x1, y1), t(x2, y2) { }
    Li(vint k, vint b) : s(0, b), t(1, k+b) { }
    Li(vint a, vint b, vint c)
    {
        if (zero(a))    // y = -c/b
            s = {1, -c/b}, t = {2, -c/b};
        else if (zero(b))   // x = -c/a
            s = {-c/a, 1}, t = {-c/a, 2};
        else
            s = {1, (-c-a)/b}, t = {0, -c/b};   // 不能是{(-c-b)/a, 1},因为这个可能和 {1, (-c-a)/b} 是同一个点!!!
    }

    void println() const {printf("("), PRT("%.3f, ", s.x), PRT("%.3f) -> (", s.y), PRT("%.3f, ", t.x), PRT("%.3f)\n", t.y);}
    vint len() const {return (t-s).len();}
    vint dist(const Po &p) const
    {
        return ABS((t-s) ^ (p-s) / (s | t));
    }
    int rel(const Po &p) const  // -1: right, 0: inside, 1: left
    {
        return sign((t-s) ^ (p-s));
    }

    Po OP &(const Li &o) const
    {
        const vint p1 = (o.t-o.s) ^ (s-o.s);
        const vint p2 = (o.t-o.s) ^ (t-o.s);
        return Po((s.x*p2 - t.x*p1)/(p2-p1), (s.y*p2 - t.y*p1)/(p2-p1));
    }
    bool OP ==(const Li &o) const {return zero((t-s) ^ (o.s-s)) && zero((t-s) ^ (o.t-s));}  // 共线
    bool OP &&(const Li &o) const {return zero((t-s) * (o.t-o.s));} // 垂直
    bool OP ||(const Li &o) const {return zero((t-s) ^ (o.t-o.s)) && !(*this==o);}  // 平行,不共线
    bool OP / (const Li &o) const {return zero((t-s) ^ (o.t-o.s));} // 平行或共线,不会有唯一交点
};



int main()
{
    vint sr, br, cr, cx, cy, vx, vy;
    Po O(0, 0);
    while (~scanf("%lf %lf %lf %lf %lf %lf %lf", &sr, &br, &cr, &cx, &cy, &vx, &vy))
    {
        Po v(vx, vy), c(0-cx, 0-cy);
        vint vabs = v.len();
        Po vn(vx / vabs, vy / vabs);
        if (sign(v * c) <= 0)
        {
            puts("0");
            continue;
        }
        Li l(c, c+v);
        vint dco = l.dist(O);
        if (sign(dco - (cr+br)) >= 0)
        {
            puts("0");
            continue;
        }

        vint xian = sqrt(sqr(cr+br) - sqr(dco));
        Po vcz(-v.y, v.x);
        Li lv(O+vcz, O);
        Po ct = lv & l;
        Po A = ct - (xian*vn);
        Po B = ct + (xian*vn);

        vint dx, dt;
        if (sign(dco - (cr+sr)) >= 0)   // 穿过
        {
            dx = dist(A, B);
            dt = dx / vabs;
        }
        else    // 碰撞
        {
            xian = sqrt(sqr(cr+sr) - sqr(dco));
            Po D = ct - (xian*vn);
            dx = dist(A, D);
            dt = dx / vabs;
            dt *= 2;
        }
        PRT("%.10f\n", dt);
    }
    return 0;
}

[G]Graph Reconstruction

题意

给出一个简单无向图的点数和每个点的度数,求是否存在这样的图.如果存在且唯一,输出方案;如果不唯一,输出任意两种方案,如果无解,则输出"IMPOSSIBLE".

题解

和CF某场比赛的题目很像.

根据Wikipedia上的某个图论定理(具体名字记不清了),首先将度数从大到小排序,然后取出度数最大的点,向后面的点依次连边,被连边的点的度数减1.之后重复以上步骤,直到所有点的度数全变成0.当某个点在被连边时度数为0,说明无解.如果某时刻最后一个连边的点的后一个点的度数不为0,则说明有多解;否则解唯一.

当有多组解时,在连最后一条边的时候跳过本该连接的点,转而和后一个度数非零的点连边,这样就构造出了第二种方案.但是,根据其他队的实验.原题貌似没写SPJ,构造解的方法必须和样例透露出的方法完全一致才能AC.辣鸡出题人.

代码

非比赛AC版,但是在有SPJ的条件下应该没问题

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#define N 257
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;

int n,m,i,j,flag,cnt;
int v[N];
int l[N][N];
int Ans[8*N*N],ans[8*N*N];

struct Data{
    int x,id;
}d[N],dd[N];

inline int Abs(int x){return (x<0)?-x:x;}
inline void Swap(int &a,int &b){a^=b^=a^=b;}
inline int Min(int a,int b){return (a<b)?a:b;}
inline int Max(int a,int b){return (a>b)?a:b;}

inline int read(){
    int p=0;    char    c=getchar();
    while (c<48||c>57)  c=getchar();
    while (c>=48&&c<=57)    p=(p<<1)+(p<<3)+c-48,c=getchar();
    return p;
}

inline bool cmp(Data x,Data y){return x.x>y.x;}

inline void Work(){
    int i=0,p=0,q=0;
    memset(l,0,sizeof(l));
    for (i=1;i<=n;i++){
        sort(d+i,d+i+n,cmp);
        /*for (j=i;j<=n;j++)
            printf("%d ",d[j].x);
        cout<<endl;*/
        p=d[i].id;
        if (!d[i].x)    break;
        for (j=i+1;j<=i+d[i].x;j++){
            l[p][d[j].id]=1;    l[d[j].id][p]=1;
            d[j].x--;
            if (d[j].x<0){
                flag=2; return;
            }
        }
        if (d[j].x>0)   flag=1;
    }
}

inline void Find(){
    int i=0,p=0,q=0;
    memset(l,0,sizeof(l));
    for (i=1;i<=n;i++){
        sort(d+i,d+i+n,cmp);
        /*for (j=i;j<=n;j++)
            printf("%d ",d[j].x);
        cout<<endl;*/
        p=d[i].id;
        if (!d[i].x)    break;
        for (j=i+1;j<=i+d[i].x;j++){
            l[p][d[j].id]=1;    l[d[j].id][p]=1;
            d[j].x--;
        }
        d[i].x=0;
        if (d[j].x==d[j-1].x+1&&d[j].x>0){
            l[p][d[j-1].id]=0;  l[d[j-1].id][p]=0;
            l[p][d[j].id]=1;    l[d[j].id][p]=1;
            d[j-1].x++; d[j].x--;
        }
    }
}

int main(){
    while (~scanf("%d",&n)){
        m=0;
        memset(d,0,sizeof(d));  memset(dd,0,sizeof(dd));
        for (i=1;i<=n;i++){
            scanf("%d",&d[i].x);
            d[i].id=i;  m+=d[i].x;
            dd[i]=d[i];
        }
        if (n==1){
            if (d[1].x==0){
                printf("UNIQUE\n");
                printf("1 0\n");
                cout<<endl;
                cout<<endl;
                continue;
            }   else {
                printf("IMPOSSIBLE\n");
                continue;
            }
        }


        flag=0; cnt=0;  m/=2;
        Work();
        if (flag==2){
                printf("IMPOSSIBLE\n");
                continue;
        }


        if (flag==0)    printf("UNIQUE\n");
        else printf("MULTIPLE\n");
        printf("%d %d\n",n,m);
        cnt=0;
        memset(ans,0,sizeof(ans));
        memset(Ans,0,sizeof(Ans));
        for (i=1;i<=n;i++)
            for (j=i+1;j<=n;j++)
                if (l[i][j])    {
                    ++cnt;
                    ans[cnt]=i; Ans[cnt]=j;
                }
        for (i=1;i<=cnt;i++)    printf("%d ",ans[i]);
        cout<<endl;
        for (i=1;i<=cnt;i++)    printf("%d ",Ans[i]);
        cout<<endl;
        if (flag==0)    continue;
        for (i=1;i<=n;i++)  d[i]=dd[i];
        Find();
        cnt=0;
        memset(ans,0,sizeof(ans));
        memset(Ans,0,sizeof(Ans));
        printf("%d %d\n",n,m);
        for (i=1;i<=n;i++)
            for (j=i+1;j<=n;j++)
                if (l[i][j])    {
                    ++cnt;
                    ans[cnt]=i; Ans[cnt]=j;
                }
        for (i=1;i<=cnt;i++)    printf("%d ",ans[i]);
        cout<<endl;
        for (i=1;i<=cnt;i++)    printf("%d ",Ans[i]);
        cout<<endl;
    }
    return 0;
}

[H]Skycity

题意

给出一个n层建筑,每一层的形状是一个圆柱体.给出建筑的总高度,高度平均分配,现在要求在每一层建筑外面贴一个多边形的瓷砖,要求圆柱体和外面的多边形相切,且外面瓷砖的面积不能小于某个定值.求最小的瓷砖面积是多少.

题解

计算几何,二分每一层的多边形边数,然后计算面积再统计即可.

代码

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
using namespace std;

double R, r, H, S;
double eps = 1e-8;
int F;

int main(){
    double pi = acos(-1);
    while(scanf("%lf%lf%lf%d%lf", &R, &r, &H, &F, &S) == 5) {
        double h = H/F;
        double ans = 0;
        for (int i = 0; i < F; i++) {
            double rx = 1.0*i/(F)*(R-r) + r;
            int x = 3, y = 10000000;
            while(y > x) {
                int k = (x+y) >> 1;
                k++;
                double l = 2*rx*tan(pi/k);
                if (l*h >= S) x = k;
                else y = k-1;
            }
            /*
            while(1) {
                int t = x+1;
                double l = 2*rx*tan(pi/t);
                printf("%lf %lf\n", 2*rx*tan(pi/x)*h, l*h);
                if (l*h >= S) x = t;
                else break; 
            }*/
            double l = 2*tan(pi/x);
            ans += rx * x * l * h;
        }
        printf("%.3lf\n", ans);
    }
    return 0;
}

[J]Josephina and RPG

题意

有n支AI队伍进行比赛,给出队伍之间对战的胜率.然后给出敌方的出战顺序,一开始可以选定一支AI队伍开始和敌方对战.每场对战胜利后,可以选择切换成刚刚击败的队伍进行下面的比赛,也可以不切换.求q场比赛后的最高胜率是多少.

题解

设第i场敌方出战的AI是t[i],f[i][j]表示第i场使用j队伍的最高胜率,则有如下转移方程:

f[i+1][j]=Max(f[i+1][j],f[i][j]*win[j][t[i+1]])

f[i+1][t[i]]=Max(f[i+1][t[i]],f[i][j]*win[t[i]][t[i+1]])

表示是否切换队伍,然后取最后一次比赛的最大值即可.

比赛时代码莫名RE,根据赛后测试,输入数据存在越界的情况......辣鸡出题人!

代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
using namespace std;

int n,m,i,j,q;
double Ans;
double dp[20010][255];
double a[255][255];
int t[20010];

inline double Max(double a,double b){return (a>b)?a:b;}

int main(){
    while (~scanf("%d",&m)){
        n=m*(m-1)*(m-2)/6;
        memset(a,0,sizeof(a));
        memset(dp,0,sizeof(dp));
        memset(t,0,sizeof(t));
        Ans=0;
        for (i=1;i<=n;i++)
            for (j=1;j<=n;j++)
                scanf("%lf",&a[i][j]);
        scanf("%d",&q);
        for (i=1;i<=q;i++)  scanf("%d",&t[i]),t[i]++;
        if (q==1){
            for (i=1;i<=n;i++)
                Ans=Max(Ans,a[i][t[1]]);
            printf("%.10lf\n",Ans);
            continue;
        }
        for (i=1;i<=n;i++)  dp[1][i]=a[i][t[1]];
        for (i=1;i<q;i++)
            for (j=1;j<=n;j++){
                dp[i+1][j]=Max(dp[i+1][j],dp[i][j]*a[j][t[i+1]]);
                dp[i+1][t[i]]=Max(dp[i+1][t[i]],dp[i][j]*a[t[i]][t[i+1]]);
            }
        for (i=1;i<=n;i++)  Ans=Max(Ans,dp[q][i]);
        printf("%.10lf\n",Ans);
    }
    return 0;
}

[K]Pocket Cube

题意

给出一个二阶魔方各个位置的编号方式以及染色情况,求在至多旋转N步(1步的定义是让某一面旋转90度,方向任意)的情况下至多拼好几个面.

题解

大模拟.

代码

有待补充

总结&吐槽

有史以来做的最辣鸡的一套题,没有之一.J题数据越界导致莫名RE,吃了两次罚时加上不可忽略的Debug和代码重构时间,间接导致K题没有写完.G题莫名WA,赛后交流发现应该是根本就没有SPJ或者SPJ写的和出题人一样辣鸡.这种情况排名也没什么意义了,不想多说什么.GTMD出题人.

说点什么
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...