2013 Multi-University Training Contest 3

11 篇文章 0 订阅
8 篇文章 0 订阅

全队就我一开始敲出了一道签到题1007The Unsolvable Problem。。。之后就各种被虐啊。。。

没算法,只能说是YY出来的。题意就是让你求出n=a+b,a和b的最大的最小公倍数,首先考虑奇数,当奇数被拆为n=x+(x+1)时,x和(x+1)为互质数,直接相乘得到答案,而偶数的话,2直接特判==1,再看其它偶数,当偶数除以2为奇数时,上下加减1肯定为两个偶数,最小公倍数必然不能取最大,所以应上下加减2,然后相乘得到答案。而当偶数除以2为偶数时,上下加减1互为奇数(互质),然后相乘得到答案。

#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<iomanip>
#include<cstdio>
using namespace std;
int main()
{
    int t;
    __int64 n;
    cin>>t;
    while(t--)
    {
        cin>>n;
        if(n==2)
        {
            cout<<1<<endl;
            continue;
        }
        if(n%2==1)
        {
            cout<<(n/2)*(n/2+1)<<endl;
        }
        else
        {
            if((n/2)%2==0)
            {
                cout<<(n/2-1)*(n/2+1)<<endl;
            }
            else
            {
                cout<<(n/2-2)*(n/2+2)<<endl;
            }
        }
    }
    return 0;
}

1011 Sad Love Story

比赛中后期一直在敲这题,发现是个求多次最近点对的问题,一开始用分治法求,O(n^2logn),复杂度太高TLE,后来学长写了KD-tree,发现还是TLE,赛后看标程才理解了,不需要求多次,先求一次全部点的最近点对,对于之前的点就不需要算了,然后去掉了一部分点,直到找到最后点为止。解题报告说KD-tree也可以做,但是要常数优化,表示不懂。。。。

#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<iomanip>
#include<cstdio>
#define MAXN 500010
using namespace std;
struct xl
{
    long long x,y,id,in;
    xl(long long xx=0,long long yy=0,long long iin=0)
    {
        x=xx;
        y=yy;
        in=iin;
    }
}P[MAXN],p[MAXN],tmpt[MAXN];
struct zx
{
    long long f,s;
}e;
long long dd(xl a,xl b)
{
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp1(xl a,xl b)
{
    if(a.x != b.x)
    {
        return a.x<b.x;
    }
    else
    {
        return a.y<b.y;
    }
}
bool cmp2(xl a,xl b)
{
    return a.y<b.y;
}
zx XLL(long long lw,long long hi)
{
    int i,j,k;
    long long d=(1LL<<60),mid,d1,d2;
    if(lw==hi)
    {
        e.f=lw;
        e.s=hi;
        return e;
    }
    if(lw+1==hi)
    {
        e.f=lw;
        e.s=hi;
        return e;
    }
    mid=(lw+hi)/2;
    zx pr1=XLL(lw,mid);
    zx pr2=XLL(mid+1,hi);
    if(pr1.f==pr1.s)
    {
        d1=(1LL<<60);
    }
    else
    {
        d1=dd(p[pr1.f],p[pr1.s]);
    }
    if(pr2.f==pr2.s)
    {
        d2=(1LL<<60);
    }
    else
    {
        d2=dd(p[pr2.f],p[pr2.s]);
    }
    zx ans;
    if(d1<d2)
    {
        ans=pr1;
    }
    else
    {
        ans=pr2;
    }
    d=min(d1,d2);
    k=0;
    for(i=lw; i<=hi; i++)
    {
        if((p[mid].x-p[i].x)*(p[mid].x-p[i].x)<=d)
        {
            tmpt[k++]=p[i];
        }
    }
    sort(tmpt,tmpt+k,cmp2);
    for(i=0; i<k; i++)
    {
        for(j=i+1; j<k&&(tmpt[j].y-tmpt[i].y)*(tmpt[j].y - tmpt[i].y) < d; j++)
        {
            if(d>dd(tmpt[i],tmpt[j]))
            {
                d=dd(tmpt[i],tmpt[j]);
                ans.f=tmpt[i].id;
                ans.s=tmpt[j].id;
            }
        }
    }
    return ans;
}
int main()
{
    int t,i;
    long long n,ax,ay,bx,by,cx,cy,w,Max,x,y,ans;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%I64d%I64d%I64d%I64d%I64d%I64d%I64d",&n,&ax,&bx,&cx,&ay,&by,&cy);
        P[0]=xl(0,0,0);
        for(i=1; i<=n; i++)
        {
            x=(P[i-1].x*ax+bx)%cx;
            y=(P[i-1].y*ay+by)%cy;
            P[i]=xl(x,y,i);
        }
        w=n;
        ans=0;
        while(w>1)
        {
            for(i=0; i<w; i++)
            {
                p[i]=P[i+1];
            }
            sort(p,p+w,cmp1);
            for(i=0; i<w; i++)
            {
                p[i].id=i;
            }
            zx pr=XLL(0,w-1);
            Max=max(p[pr.f].in,p[pr.s].in);
            ans+=(w-Max+1)*dd(p[pr.f],p[pr.s]);
            w=Max-1;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}


1008 Pieces

版刷题,可我们没过。。。敲了一上午,用状压暴力枚举做得,,,2^16的个数

#include<iostream>  
#include<cmath>  
#include<cstring>  
#include<string>  
#include<algorithm>  
#include<iomanip>  
#include<cstdio>  
#define MAXN 1<<16  
using namespace std;  
int dp[MAXN],q[MAXN];
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');
    }
}  
int main()  
{  
    int t,i,j,l,l1,f,w;  
    char a[22];  
    RD(t);
    while(t--)  
    {  
        scanf("%s",a);  
        l=strlen(a);  
        l1=1<<l;  
        for(i=1; i<l1; ++i)  
        {  
            dp[0]=MAXN;//初始化,容易出错。。。  
            w=0;  
            for(j=0; j<=l; ++j)  
            {  
                if(i&(1<<j))  
                {  
                    q[w++]=j;  
                }  
            }  
            f=0;  
            w=w-1;  
            for(j=0; j<w/2; ++j)  
            {  
                if(a[q[j]]!=a[q[w-j]])  
                {  
                    dp[i]=w+1;  
                    f=1;  
                    break;  
                }  
            }  
            if(f==0)  
            {  
                dp[i]=1;  
            }  
            for(j=i;j;j=(j-1)&i)  
            {  
                //cout<<(j^i)<<' '<<dp[(j^i)]<<endl;  
                dp[i]=min(dp[i],dp[j]+dp[j^i]);  
            }  
            //cout<<dp[i]<<endl;  
        }  
        printf("%d\n",dp[l1-1]); 
    }  
    return 0;  
}
加了个输入优化。。


1010 No Pain No Game

树状数组维护,数据结构的题表示一直不太会,而且也看不太出来。。。

#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<iomanip>
#include<cstdio>
using namespace std;
int n,c[50001];
int a[50001],b[50001],ac[50001];
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');
    }
}
int lowbit(int x)
{
    return x&(-x);
}
int add(int n)
{
    int sum=0;
    while(n>0)
    {
        sum=max(sum,c[n]);
        n-=lowbit(n);
    }
    return sum;
}
void updata(int i,int x)
{
    while(i<=n)
    {
        c[i]=max(c[i],x);
        i+=lowbit(i);
    }
}
struct xl
{
    int lw,hi,id;
} s[50001];
bool cmp(xl x,xl y)
{
    return x.lw>y.lw;
}
int main()
{
    int i,t,m,j,k;
    RD(t);
    while(t--)
    {
        RD(n);
        for(i=1; i<=n; ++i)
        {
            RD(a[i]);
        }
        RD(m);
        for(i=0; i<m; ++i)
        {
            RD(s[i].lw);
            RD(s[i].hi);
            s[i].id=i;
        }
        sort(s,s+m,cmp);
        i=n;
        j=0;
        memset(b,0,sizeof(b));
        memset(c,0,sizeof(c));
        while(j<m)
        {
            for(; i>0&&i>=s[j].lw; --i)
            {
                for(k=1; k*k<=a[i]; ++k)
                {
                    if(a[i]%k==0)
                    {
                        if(b[k]!=0)
                        {
                            updata(b[k],k);
                        }
                        b[k]=i;
                        if(a[i]/k!=k)
                        {
                            if(b[a[i]/k]!=0)
                            {
                                updata(b[a[i]/k],a[i]/k);
                            }
                            b[a[i]/k]=i;
                        }
                    }
                }
            }
            while(j<m&&s[j].lw>i)
            {
                ac[s[j].id]=add(s[j].hi);
                j++;
            }
        }
        for(i=0; i<m; ++i)
        {
            printf("%d\n",ac[i]);
        }
    }
    return 0;
}



我实在太水了。。。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值