2013 Multi-University Training Contest 5

13 篇文章 0 订阅
12 篇文章 0 订阅

1001 GSM

一道计算几何题,学长用Voronoi图模板做的,表示不太会。直接用递归二分找所有最短的点,1000多MS,慢是慢了点,不过也能过。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#define N 1e18
#define exp 1e-7
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
struct xl
{
    double a,b;
}c[55],s[55];
int n,m;
int zero(double x)//double数判正负
{
    return x>exp?1:(x<-exp?-1:0);
}
double d(xl p,xl q)
{
    return (p.a-q.a)*(p.a-q.a)+(p.b-q.b)*(p.b-q.b);
}
int g(xl t)
{
    int id,i;
    double ds=N,tmp;
    for(i=0;i<m;++i)
    {
        tmp=d(t,s[i]);
        if(zero(tmp-ds)<0)
        {
            ds=tmp;
            id=i;
        }
    }
    return id;
}
int f(xl p,xl q)//二分求解
{
    int l=g(p),r=g(q);
    xl m;
    double ds;
    if(l==r)
    {
        return 0;
    }
    else
    {
        ds=d(p,q);
        if(zero(ds)==0)
        {
            return 1;
        }
        m.a=(p.a+q.a)/2.0;
        m.b=(p.b+q.b)/2.0;
        return f(p,m)+f(m,q);
    }
}
int main()
{
    int i,q,x,y,ans;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=0;i<n;++i)
        {
            scanf("%lf%lf",&c[i].a,&c[i].b);
        }
        for(i=0;i<m;++i)
        {
            scanf("%lf%lf",&s[i].a,&s[i].b);
        }
        RD(q);
        while(q--)
        {
            RD(x);
            RD(y);
            ans=f(c[x-1],c[y-1]);
            OT(ans);
            printf("\n");
        }
    }
    return 0;
}

1004 Laser Beam

恶心的题啊,我无数次的WA,TLE,MLE,RE。各种卡。。。最后才过的。

解题报告上说只要枚举(n+3)/2边上的红点就行可以了,O(n)能过的,,可我就是再优化,也还是TLE。。。用标程的DFS过居然是0MS,,,没办法只能再想办法,最后加了各种调用优化,才终于算过了,也有一点递归。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
map<int,int>dp;
int gcd(int a,int b)
{
    if(b==0)
    {
        return a;
    }
    else
    {
        return gcd(b,a%b);
    }
}
int g(int x)
{
    if(x==1)
    {
        return 1;
    }
    int i,m=0,p=-1,q=-1,j,id,jd;
    for(i=1; i<=x; i+=3)
    {
        j=(x+3)-4*i;
        if(j<=0)
        {
            break;
        }
        if(j%6==0)
        {
            j=j/6;
            p=i;
            q=j;
            break;
        }
        id=i+1;
        jd=(x+3)-4*id;
        if(jd<=0)
        {
            break;
        }
        if(jd%6==0)
        {
            jd=jd/6;
            p=id;
            q=jd;
            break;
        }
    }
    if(p>0)
    {
        while(q>0)
        {
            if(gcd(p,q)==1)
            {
                m++;
            }
            p+=3;
            q-=2;
        }
    }
    return m*2;
}
void f()
{
    dp.clear();
    int i;
    dp[4]=1;
    dp[3]=dp[2]=dp[1]=dp[0]=0;
    for(i=1; i<=100; ++i)
    {
        dp[i+3]=g(i);
    }
}
int c(int x)
{
    int i,j;
    if(x%2!=0)
    {
        return 0;
    }
    for(i=1;; ++i)
    {
        if((x-i*4)%6==0)
        {
            j=(x-i*4)/6;
            break;
        }
    }
    if(j<=0)
    {
        return 0;
    }
    return (j+1)/2;
}
int d(int x)
{
    int i;
    if(dp.count(x))
    {
        return dp[x];
    }
    if((x-3)%6!=1&&(x-3)%6!=5)
    {
        return 0;
    }
    dp[x]=c(x)*2;
    for(i=2; i*i<=x; ++i)
    {
        if(x%i==0)
        {
            if(i>4)
            {
                dp[x]-=d(i);
            }
            if(x/i>4&&i*i<x)
            {
                dp[x]-=d(x/i);
            }
        }
    }
    return dp[x];
}
int main()
{
    int t,n,ans;
    f();
    RD(t);
    while(t--)
    {
        scanf("%d",&n);
        ans=d(n+3);
        printf("%d\n",ans);
    }
    return 0;
}

1005 Another Graph Game

想法题,谨以此题向Baoge致敬。。。a+b的难度了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define N 1000000007
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
bool cmp(double a,double b)
{
    return a>b;
}
int main()
{
    int n,m,u,v,i;
    double w,s[100001],a,b;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=1;i<=n;++i)
        {
            scanf("%lf",&s[i]);
        }
        for(i=1;i<=m;++i)
        {
            scanf("%d%d%lf",&u,&v,&w);
            s[u]+=w/2.0;
            s[v]+=w/2.0;
        }
        sort(s+1,s+n+1,cmp);
        a=0;
        b=0;
        for(i=1;i<=n;++i)
        {
            if(i%2==1)
            {
                a+=s[i];
            }
            else
            {
                b+=s[i];
            }
        }
        printf("%.0f\n",a-b);
    }
    return 0;
}

1006 Magic Pen 6

签到题,求最大能整除M的区间。O(n^2)已能过。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define N 1000000007
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
int a[100001];
int main()
{
    int n,m,i,j,s,x;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(a,0,sizeof(a));
        for(i=1;i<=n;++i)
        {
            scanf("%d",&x);
            a[i]=(a[i-1]+x)%m;
        }
        s=0;
        for(i=n;i>=1&&i>s;--i)
        {
            for(j=1;j<=n-i+1;++j)
            {
                if((a[j+i-1]-a[j-1])%m==0)
                {
                    s=max(s,i);
                    break;
                }
            }
        }
        printf("%d\n",s);
    }
    return 0;
}


1007 Professor Tian

我们唯一没过的版刷题,一道水概率DP,将数字转化为二进制,总共就20次转化,然后对‘1’,‘0’用二维数组标记,对相应的运算符进行计算。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define N 1000000007
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
int a[201];
double p[201],dp[201][2];
char s[201];
int main()
{
    int n,i,j,cas=0,x;
    double sum,pw;
    while(scanf("%d",&n)!=EOF)
    {
        cas++;
        for(i=0; i<=n; ++i)
        {
            RD(a[i]);
        }
        for(i=1; i<=n; ++i)
        {
            cin>>s[i];
        }
        for(i=1; i<=n; ++i)
        {
            scanf("%lf",&p[i]);
        }
        pw=1.0;
        sum=0.0;
        for(i=0; i<=20; ++i)
        {
            dp[0][1]=((a[0]>>i)&1);
            dp[0][0]=!dp[0][1];
            for(j=1; j<=n; ++j)
            {
                dp[j][1]=dp[j-1][1]*p[j];
                x=((a[j]>>i)&1);
                if(s[j]=='^')
                {
                    dp[j][1]+=(dp[j-1][0]*(0^x)+dp[j-1][1]*(1^x))*(1.0-p[j]);
                }
                else if(s[j]=='&')
                {
                    dp[j][1]+=(dp[j-1][0]*(0&x)+dp[j-1][1]*(1&x))*(1.0-p[j]);
                }
                else if(s[j]=='|')
                {
                    dp[j][1]+=(dp[j-1][0]*(0|x)+dp[j-1][1]*(1|x))*(1.0-p[j]);
                }
                dp[j][0]=1.0-dp[j][1];
            }
            sum+=pw*dp[n][1];
            pw*=2.0;
        }
        printf("Case %d:\n%.6f\n",cas,sum);
    }
    return 0;
}

1009 Partition

一道老题了,整数划分的情况整数,可以通过维基百科和数列公式了解一下。。。由于它没有相应的唯一公式,所以只能通过递推的方式得到。

f(n)+={f(n-i*(3*i-1))+f(n-i*(3*i+1))}*(-1)^(i+1)

加上或减去的项数为五角数公式;

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define N 1000000007
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
long long a[100001];
void f()
{
    int i,j;
    long long sum;
    a[0]=1;
    a[1]=1;
    a[2]=2;
    for(i=2;i<=100000;++i)
    {
        sum=0;
        for(j=1;(i-j*(3*j-1)/2)>=0||(i-j*(3*j+1)/2)>=0;j++)//递推式
        {
            if(j%2==1)
            {
                if((i-j*(3*j-1)/2)>=0)//注意两个都是if
                {
                    sum+=a[(i-j*(3*j-1)/2)]%N;
                }
                if((i-j*(3*j+1)/2)>=0)
                {
                    sum+=a[(i-j*(3*j+1)/2)]%N;
                }
            }
            else
            {
                if((i-j*(3*j-1)/2)>=0)
                {
                    sum=(sum-a[(i-j*(3*j-1)/2)]+N)%N;//防止为负数,我因为这个WA了
                }
                if((i-j*(3*j+1)/2)>=0)
                {
                    sum=(sum-a[(i-j*(3*j+1)/2)]+N)%N;
                }
            }
        }
        a[i]=sum;
    }
}
int main()
{
    f();
    int t,n;
    RD(t);
    while(t--)
    {
        cin>>n;
        cout<<a[n]%N<<endl;
    }
    return 0;
}

1011 k-th point

公式题,不解释,知道你就能AC,不知道的只能寄希望于强悍的数学推导能力或者YY猜公式的能力。。。

我YY到公式时,学长也正好找到了公式:i*p/(i*p+1)连乘 (i=>n-k~n)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define exp 1e-10
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
int main()
{
    int t,n,k,i;
    double sum,p;
    RD(t);
    while(t--)
    {
        cin>>p>>n>>k;
        sum=1.0;
        for(i=n-k;i<=n;++i)
        {
            sum=sum*(i*p)/(i*p+1.0);
        }
        printf("%.9f\n",sum);
    }
    return 0;
}

这次表现不错,但还是差距很大。。。继续努力!


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值