2013 成都邀请赛

           今年又要打邀请赛了,前段时间做比赛都被虐的够呛。感觉不会再爱了。。。所以挂了下去年的成都邀请赛的题目。发现简单题还是能切上几道的,可是难题就无能为力了。。

。阿门,还是水平差得远啊。。

(ps:近期感觉状态不佳。依靠了队友神勇的发挥。

。。

         

Current Time: 2014-05-15 08:43:24 Contest Type: Public
Start Time: 2014-05-14 15:10:00 Contest Status: Ended
End Time: 2014-05-14 20:10:00 Manager: ok_again

           A,一如既往的最签到的题目。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define eps 1e-8
#define PI acos(-1.0)
#define maxn 22000
#define INF 0x3f3f3f3f
#define E exp(double(1))
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

#ifdef __int64
    typedef __int64 LL;
#else
    typedef long long LL;
#endif

int main(){
    int i,j,k,a,b;
    int _,cas=1;
    cin>>_;
    while(_--){
        cin>>a;
        a/=10;
        printf("Case #%d:
",cas++);
        puts("*------------*");
        b=a;
        a=10-a;
        while(a--){
            puts("|............|");
        }
        while(b--){
            puts("|------------|");
        }
        puts("*------------*");
    }
    return 0;
}

           B题找的是最长的距离最短。是一个下凹的图形,直接三分就可以。

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
const double eps=1e-8;
struct point{
    double x,y;
    point(double a=0,double b=0){
        x=a,y=b;
    }
    point operator+(const point &a){
        return point(a.x+x,a.y+y);
    }
    point operator*(const double &a){
        return point(x*a,y*a);
    }
    void input(){
        scanf("%lf%lf",&x,&y);
    }
}p[500],vp[500],tmp[500];
int n;
double dist(point a,point b){
    double x=a.x-b.x;
    double y=a.y-b.y;
    return sqrt(x*x+y*y);
}
double calc(double t){
    for(int i=0;i<n;i++) tmp[i]=p[i]+vp[i]*t;
    double res=-1;
    for(int i=0;i<n;i++){
        for(int j=i+1;j<n;j++) res=max(res,dist(tmp[i],tmp[j]));
    }
    return res;
}
int main(){
    int t;
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++){
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            p[i].input(),vp[i].input();
        }
        double l=0,r=1e20,mid,midmid;
        double ans=0;
        while(l+eps<r){
            mid=(l+r)/2;
            midmid=(mid+r)/2;
            double mid_=calc(mid);
            double midmid_=calc(midmid);
            if(mid_<midmid_){
                r=midmid;ans=mid_;
            }
            else l=mid;
        }
        printf("Case #%d: ",cas);
        printf("%.2f %.2f
",l,ans);
    }
}

           C题好像能够用LCA。保存6个值。各自是该区间的最长连续上升序列长度,左右端点连续上升序列长度,和分别得下降序列长度,便于查询时衔接用。

。。

比赛的时候想到了,可是没敲。。

。所以这题代码就不给了。

。。

            D题好题线段树+dp+单调性。比赛的时候剩余时间不多了,没怎么想到正解。

。。后来看了下大家用的是线段树。自己想了想。的确能够用线段树维护。。。

当时就哭了。线段树中维护的是长度为L的那一段中,高度区间中dp[i]-h[i]的值(保存这个是由于。那个递推式。应该非常明显能看出来)。然后就是怎么往树中加点和删点了,明显,同一高度的假设后面出现的val值比掐面出现的val值还要大的话。前面哪一个肯定是无用的,所以我们须要维护每一个高度整体单调递减,然后删除的时候推断一下当前删除点是否在树中就能够了。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define eps 1e-7
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define E exp(double(1))
#define CLR(a, b) memset(a, b, sizeof(a))
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
using namespace std;

#ifdef __int64
typedef __int64 LL;
#else
typedef long long LL;
#endif

const int maxn = 222222;

LL MAX[maxn<<2];
int fir[maxn], nxt[maxn], h[maxn], pre[maxn], last[maxn];

void PushUP(int rt)
{
    MAX[rt] = max(MAX[rt<<1] , MAX[rt<<1|1]);
}
void update(int p,LL sc,int l,int r,int rt)
{
    if (l == r)
    {
        MAX[rt] = sc;
        return ;
    }
    int m = (l + r) >> 1;
    if (p <= m) update(p , sc , lson);
    else update(p , sc , rson);
    PushUP(rt);
}

LL query(int L,int R,int l,int r,int rt)
{
    if (L <= l && r <= R)
    {
        return MAX[rt];
    }
    int m = (l + r) >> 1;
    LL ret = -5;
    if (L <= m) ret = max(ret , query(L , R , lson));
    if (R > m) ret = max(ret , query(L , R , rson));
    return ret;
}

LL dp[maxn];

void work(int cas)
{
    int n, l;
    scanf("%d%d", &n, &l);
    for(int i = 1; i <= n; i ++)
    {
        scanf("%d", &h[i]);
    }
    CLR(MAX, -1);CLR(dp, -1);
    CLR(pre, -1);
    printf("Case #%d: ", cas);
    for(int i = 1; i <= n; i ++)
    {
        LL tmp;
        if(h[i] == 1) tmp = -1;
        else tmp = query(1, h[i] - 1, 1, 100000, 1);
        if(tmp == -1 && i > l)
        {
            goto ed;
        }
        if(tmp == -1) tmp = 0;
        tmp += 1ll*h[i]*h[i] - h[i];
        dp[i] = tmp;
        int j;
        for(j = pre[h[i]]; j != -1; j = last[j])
        {
            if(dp[j] > dp[i]) break;
        }
        if(j == -1)
        {
            pre[h[i]] = i;
            fir[h[i]] = i;
            last[i] = -1;
            update(h[i], dp[i], 1, 100000, 1);
        }
        else
        {
            pre[h[i]] = i;
            nxt[j] = i;
            last[i] = j;
        }
        if(i <= l) continue;
        ed:;
        if(fir[h[i - l]] == i - l)
        {
            if(pre[h[i - l]] == fir[h[i - l]])
            {
                pre[h[i - l]] = -1;
                update(h[i - l], -1, 1, 100000, 1);
            }
            else
            {
                fir[h[i - l]] = nxt[fir[h[i - l]]];
                update(h[i - l], dp[fir[h[i - l]]], 1, 100000, 1);
            }
        }
    }
    if(dp[n] == -1) puts("No solution");
    else printf("%I64d
", dp[n] + h[n]);
}

int main()
{
    int T, cas = 1;
    scanf("%d", &T);
    while(T --)
    {
        work(cas ++);
    }
}

/*
555
5 1
24 5452 3542 452 14
*/

              E题,这道题队友兴冲冲的就上去敲了。表示全然不知道题目。。。只是还是把代码附上吧。

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;
const double eps=1e-8;
struct point{
    double x,y;
    point(double a=0,double b=0){
        x=a,y=b;
    }
    void input(){
        scanf("%lf%lf",&x,&y);
    }
}p[4],now,ori;
double r;
double dist(point a,point b){
    double x=a.x-b.x;
    double y=a.y-b.y;
    return sqrt(x*x+y*y);
}
point getpoint(point a,point b,point c){
    double bx=b.x-a.x,by=b.y-a.y;
    double cx=c.x-a.x,cy=c.y-a.y;
    double d=2*(bx*cy-by*cx);
    double x=(cy*(bx*bx+by*by)-by*(cx*cx+cy*cy))/d+a.x;
    double y=(bx*(cx*cx+cy*cy)-cx*(bx*bx+by*by))/d+a.y;
    return point(x,y);
}
void MiniOver(){
    ori=p[0];r=0;
    for(int i=1;i<3;i++){
        if(dist(ori,p[i])+eps>r){
            ori=p[i],r=0;
            for(int j=0;j<i;j++)
                if(dist(ori,p[j])+eps>r){
                    ori.x=(p[i].x+p[j].x)/2;
                    ori.y=(p[i].y+p[j].y)/2;
                    r=dist(ori,p[j]);
                    for(int k=0;k<j;k++)
                        if(dist(ori,p[k])+eps>r){
                            ori=getpoint(p[i],p[j],p[k]);
                            r=dist(ori,p[k]);
                        }
                }
        }
    }
}
int main(){
    int t;
    scanf("%d",&t);
    for(int i=1;i<=t;i++){
        for(int j=0;j<3;j++) p[j].input();
        MiniOver();
        now.input();
        printf("Case #%d: ",i);
        if(dist(now,ori)<=r) puts("Danger");
        else puts("Safe");
    }
}

           G题是一道简单的数位dp。

忘了0的情况。

。。

检查了n久。罪过啊。dp[i][j]表示长度为i位。余数为j有多少种数(包含前导零)。然后就显然了。。。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define eps 1e-7
#define PI acos(-1.0)
#define maxn 300
#define INF 0x3f3f3f3f
#define E exp(double(1))
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

#ifdef __int64
typedef __int64 LL;
#else
typedef long long LL;
#endif

LL dp[20][15];

void init()
{
    CLR(dp, 0);
    dp[0][0] = 1;
    for(int i = 1; i < 20; i ++)
    {
        for(int j = 0; j < 10; j ++)
        {
            for(int k = 0; k < 10; k ++)
            {
                dp[i][(j + k) % 10] += dp[i - 1][j];
            }
        }
    }
}

int c[25];

LL cal(LL a)
{
    int len = 0;
    while(a)
    {
        c[len ++] = a % 10;
        a /= 10;
    }
    LL ret = 0;
    int sum = 0;
    for(int i = len - 1; i >= 0; i --)
    {
        if(i) for(int j = 1; j < 10; j ++)
        {
            ret += dp[i - 1][(10 - j)%10];
        }
        for(int j = 0; j < c[i]; j ++)
        {
            if(i == len - 1 && j == 0)
            {
                sum = (sum + 1) % 10;
                continue;
            }
            ret += dp[i][(10 - sum) % 10];
            sum = (sum + 1) % 10;
        }
    }
    return ret;
}

int main()
{
    int T, cas = 1;
    init();
    scanf("%d", &T);
    while(T --)
    {
        LL a, b;
        scanf("%I64d%I64d", &a, &b);
        printf("Case #%d: ", cas ++);
        LL ans = cal(b + 1) - cal(a);
        if(a == 0) ans ++;
        printf("%I64d
", ans);
    }
}

            H题,贪心一下就好了。最左边上下两点可定要连线,然后分别捡短的线连就能够了。。。

(正确性不可证。画了下图感觉挺对的。

。)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define eps 1e-7
#define PI acos(-1.0)
#define maxn 100100
#define inf 0x3f3f3f3f
#define E exp(double(1))
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

#ifdef __int64
    typedef __int64 LL;
#else
    typedef long long LL;
#endif

int c[maxn], d[maxn], ca;

double len(int i, int j)
{
    return sqrt(1.0*ca*ca + 1.0*(c[i] - d[j])*(c[i] - d[j]));
}

int main()
{
    int T, cas = 1;
    int n, m, a, b;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d%d", &a, &b);
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; i ++)
        {
            scanf("%d", &c[i]);
        }
        for(int i = 0; i < m; i ++)
        {
            scanf("%d", &d[i]);
        }
        int y1, y2; ca = abs(a - b); double ans = 0.0;
        ans += len(0, 0);
        for(y1 = 0, y2 = 0; y1 < n && y2 < m;)
        {
            double tmp1 = 1e20, tmp2 = 1e20;
            if(y1 == n - 1 && y2 == m - 1) break;
            if(y1 < n - 1) tmp1 = len(y1+1, y2);
            if(y2 < m - 1) tmp2 = len(y1, y2+1);
            if(tmp1 < tmp2) ans += tmp1, y1 ++;
            else ans += tmp2, y2 ++;
        }
        printf("Case #%d: %.2f
", cas ++, ans);
    }
}

              J题想了n久才想到正解。。。本来想敲spfa的,队友说他先前敲的dij还在。就让他上去改了。

。。

大概就是我们须要把每一层都都当做一个节点。这种话第i层的点是能够更新第i+1层的全部点的,我们仅仅需把代表第i+1层的点更新了就能够了。。层节点代表的整层的信息。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define eps 1e-7
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define E exp(double(1))
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

#ifdef __int64
typedef __int64 LL;
#else
typedef long long LL;
#endif

#define maxn 201000
#define maxe 601000

struct Edge{
    int from,to,dis,next;
}edge[maxe];
int head[maxn];
int n,m,c,cnt;
void add(int q,int h,int len){
    edge[cnt].from=q;
    edge[cnt].to=h;
    edge[cnt].dis=len;
    edge[cnt].next=head[q];
    head[q]=cnt;
    cnt++;
}
void init(){
    cnt=0;
    memset(head,-1,sizeof head);
}

int belong[maxn];
vector<int>v[maxn];

struct node{
    int u,c;
    node(int u,int c):u(u),c(c){};
    node(){};
    friend bool operator <(node a,node b){
        return a.c>b.c;
    }
}tmp;
int can[maxn];
int dis[maxn];
bool used[maxn];
priority_queue<node>q;
void dij(int s,int ttt){
    int t,u,w;
    while(!q.empty())q.pop();
    memset(used,0,sizeof used);
    memset(dis,inf,sizeof dis);
    tmp=node(s,0);
    dis[s]=0;
    q.push(tmp);
    if(belong[s]+1<=2*n && can[belong[s]+1]){
        tmp=node(belong[s]+1,c);
        dis[belong[s]+1]=c;
        q.push(tmp);
    }
    if(belong[s]-1>n && can[belong[s]-1]){
        tmp=node(belong[s]-1,c);
        dis[belong[s]-1]=c;
        q.push(tmp);
    }
    while(!q.empty()){
        tmp=q.top();
        q.pop();
        t=tmp.u;
        if(used[t])continue;
        else used[t]=true;
        for(int i=head[t];i!=-1;i=edge[i].next){
            u=edge[i].to;
            w=edge[i].dis;
            if(used[u])continue;
            if(dis[t]+w<dis[u]){
                dis[u]=dis[t]+w;
                q.push(node(u,dis[u]));
                if(u<=n){
                    if(belong[u]<=n*2 && can[belong[u]+1] && dis[t]+w+c < dis[ belong[u]+1 ]){
                        dis[ belong[u]+1 ]=dis[t]+w+c;
                        q.push(node(belong[u]+1,dis[t]+w+c));
                    }
                    if(belong[u]-1>n && can[belong[u]-1] && dis[t]+w+c < dis[ belong[u]-1 ]){
                        dis[ belong[u]-1 ]=dis[t]+w+c;
                        q.push(node(belong[u]-1,dis[t]+w+c));
                    }
                }
            }
        }
        if(t>n){
            if(t<=n*2 && can[t+1] && dis[t]+c < dis[ t+1 ]){
                dis[ t+1 ]=dis[t]+c;
                q.push(node(t+1,dis[t]+c));
            }
            if(t-1>n && can[t-1] && dis[t]+c < dis[ t-1 ]){
                dis[ t-1 ]=dis[t]+c;
                q.push(node(t-1,dis[t]+c));
            }
        }
    }
}

inline int get_int(){
    int ret=0;
    char c;
    while(!isdigit(c=getchar()));
    do{
        ret =(ret<<3)+(ret<<1)+c-'0';
    }while(isdigit(c=getchar()));
    return ret;
}



int main(){
    int _,cas=1,q,h,cost;
    cin>>_;
    while(_--){
        n=get_int(),m=get_int(),c=get_int();
        init();
        memset(can,0,sizeof can);
        for(int i=1;i<=n;i++){
            belong[i]=get_int();
            belong[i]+=n;
            can[belong[i]]=1;
        }

        for(int i=0;i<m;i++){
            q=get_int(),h=get_int(),cost=get_int();
            add(belong[q],h,cost);
            add(belong[h],q,cost);
            add(q,h,cost);
            add(h,q,cost);
        }

        dij(1,n);
        printf("Case #%d: ",cas++);

        int ans=min(dis[belong[n]],dis[n]);


        if(ans==inf){
            puts("-1");
        }else{
            printf("%d
",ans);
        }
    }
    return 0;
}

            K题是一道计数题?没看题。。。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define eps 1e-8
#define PI acos(-1.0)
#define maxn 2200000
#define INF 0x3f3f3f3f
#define E exp(double(1))
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

#ifdef __int64
    typedef __int64 LL;
#else
    typedef long long LL;
#endif

char s[maxn];
int c1[11];
int cp1[11];
int cp2[11];
int c2[11];
int x1,x2;
int cnt[11];
int ctt[11];

int gethead(){
    for(int i=9;i>=0;i--){
        for(int j=0;j<=9;j++){
            int tt = (i-j);
            if(tt<0)tt+=10;
            if(j==0||tt==0)continue;
            if(c1[j]&&c2[tt]){
               return i;
            }
        }
    }
}


void getnext(){

    for(int sum=9;sum>=0;sum--){
        for(int a=0;a<=9;a++){
            int b = (sum-a);
            if(b<0)b+=10;
            int cc = min(c1[a],c2[b]);
            c1[a]-=cc;
            c2[b]-=cc;
            cnt[sum]+=cc;
        }
    }

    bool ok;
    for(int i=9;i>=0;i--){
        if(cnt[i]==ctt[i])continue;
        if(cnt[i]<ctt[i])ok=false;
        else ok=true;
        break;
    }
    if(ok){
        for(int i=0;i<=9;i++){
            ctt[i]=cnt[i];
        }
    }
}


int main(){
    int _,cas=1;
    cin>>_;
    while(_--){
        memset(c1,0,sizeof c1);
        memset(c2,0,sizeof c2);
        memset(cnt,0,sizeof cnt);
        memset(ctt,0,sizeof ctt);
        scanf("%s",s);
        for(int i=0;s[i];i++)c1[s[i]-'0']++;
        scanf("%s",s);
        for(int i=0;s[i];i++)c2[s[i]-'0']++;
        int h = gethead();

        for(int i=0;i<=9;i++){
            cp1[i]=c1[i];
            cp2[i]=c2[i];
        }

        for(int i=0;i<=9;i++){
            for(int j=0;j<=9;j++){
                c1[j]=cp1[j];
                c2[j]=cp2[j];
            }
            int tt = (h-i);
            if(tt<0)tt+=10;
            if(i==0||tt==0)continue;
            if(c1[i]&&c2[tt]){
                c1[i]--;
                c2[tt]--;
                memset(cnt,0,sizeof cnt);
                getnext();
            }
        }

        bool ok=false;
        if(h!=0)ok=true;
        printf("Case #%d: ",cas++);
        if(h!=0)printf("%d",h);
        for(int i=9;i>=1;i--){
            while(ctt[i]--){
                printf("%d",i);
                ok=true;
            }
        }
        if(ok){
             while(ctt[0]--){
                printf("%d",0);
            }
        }else{
            printf("0");
        }
        puts("");
    }
    return 0;
}

              L题,第二签到题。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define eps 1e-8
#define PI acos(-1.0)
#define maxn 220000
#define INF 0x3f3f3f3f
#define E exp(double(1))
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

#ifdef __int64
    typedef __int64 LL;
#else
    typedef long long LL;
#endif

int s[maxn];

int main(){
    int i,j,k,n,b;
    int _,cas=1;
    cin>>_;
    while(_--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&s[i]);
        }
        b=-1;
        for(int i=2;i<=n;i++){
            if(s[i]-s[i-1]!=1){
                b=i;
            }
            if(~b)break;
        }
        if(b==-1)b=1;
        printf("Case #%d: %d
",cas++,b);
    }
    return 0;
}