2018 ACM 国际大学生程序设计竞赛上海大都会赛重现赛

A
由于小数点之后只有一位,可以随机一下。

#include<bits/stdc++.h>
using namespace std;
const int canshu=10;
int cs;
int t,n;
double x;

struct node{
    double x,y;
    int num;
}a[10005];

int tot;

bool cmp(node a, node b){
    if(a.num!=b.num)
        return a.num>b.num;
    else if(a.x!=b.x)
        return a.x<b.x;
    else return a.y<b.y;
}

void quchong(){
    tot=n;
    sort(a,a+n,cmp);
    int j=-1;
    for(int i=0; i<n; i++){
        if(j==-1 || a[i].x!=a[j].x || a[i].y!=a[j].y){
            j=i;
        }
        else{
            a[j].num+=a[i].num;
            a[i].num=0;
            tot--;
        }
    }
    sort(a,a+n,cmp);
    /*
    cout<<tot<<endl;
    for(int i=0; i<tot; i++){

    }
    */
    return;
}

inline bool check(node a, node b, node c){
    return (b.y-a.y)*(c.x-a.x)==(b.x-a.x)*(c.y-a.y);
}

int main(){
    scanf("%d",&t);
    srand(time(0));
    for(int tt=1; tt<=t; tt++){
        scanf("%d%lf",&n,&x);
        for(int i=0; i<n; i++){
            scanf("%lf%lf",&a[i].x,&a[i].y);
            a[i].num=1;
        }
        quchong();
        if(tot==1){
            printf("Yes\n");
            continue;
        }
        cs=1.0*canshu/(x*x);
        int m;
        bool flag=0;
        //cout<<"cs:"<<cs<<endl;
        for(int k=0; k<cs; k++){
            int l=0,r=0;
            l=rand()%tot;
            r=rand()%tot;
            while(r==l)
                r=rand()%tot;
            m=a[l].num+a[r].num;
            for(int i=0; i<tot; i++){
                if(i==l || i==r) continue;
                if(check(a[l],a[r],a[i]))
                    m+=a[i].num;
            }
            //cout<<l<<" "<<r<<" : "<<m<<endl;
            if(1.0*m>=x*n){
                flag=1;
                break;
            }
        }
        if(flag) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

B
签到。

#include<bits/stdc++.h>
using namespace std;
int t,n;
int tot=0,ans[100005],sum;
int main(){
    scanf("%d",&t);
    for(int tt=1; tt<=t; tt++){
        scanf("%d",&n);
        sum=0;
        tot=0;
        int i;
        for(i=1; i*i<n; i++){
            if(n%i==0){
                ans[tot++]=i;
                sum+=i+n/i;
            }
        }
        if(i*i==n) sum+=i;
        //cout<<sum<<endl;
        if(sum==2*n){
            printf("Case %d: %d = 1",tt,n);
            for(i=1; i<tot; i++)
                printf(" + %d",ans[i]);
            for(int i=tot-1; i>0; i--)
                printf(" + %d",n/ans[i]);
            printf("\n");
        }
        else{
            printf("Case %d: Not perfect.\n",tt);
        }

    }
    return 0;
}

C
先判断两个线段的公垂线是否与线段相交,是的话就是交点之间的距离,否则就是每个端点到另一条线段的距离。

#include<bits/stdc++.h>
using namespace std;
//#define eps 1e-8
//#define zero(x) (((x)>0?(x):-(x))<eps)
#define distance dis
#define ll long long
const ll inf=1e9;
struct point3{ll x,y,z;};
struct line3{point3 a,b;};
struct plane3{point3 a,b,c;};

struct myfloat{
    ll p,q;
};

bool operator < (const myfloat a, const myfloat b){
    return a.p*b.q<b.p*a.q;
}

//计算 cross product U x V
point3 xmult(point3 u,point3 v){
    point3 ret;
    ret.x=u.y*v.z-v.y*u.z;
    ret.y=u.z*v.x-u.x*v.z;
    ret.z=u.x*v.y-u.y*v.x;
    return ret;
}

//计算 dot product U . V
ll dmult(point3 u,point3 v){
    return u.x*v.x+u.y*v.y+u.z*v.z;
}

//矢量差 U - V
point3 subt(point3 u,point3 v){
    point3 ret;
    ret.x=u.x-v.x;
    ret.y=u.y-v.y;
    ret.z=u.z-v.z;
    return ret;
}

//两点距离,单参数取向量大小
ll distance(point3 p1,point3 p2){
    return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)+(p1.z-p2.z)*(p1.z-p2.z);
}

//向量大小
ll vlen(point3 p){
    return p.x*p.x+p.y*p.y+p.z*p.z;
}

myfloat ptoline(point3 p,line3 l){
    return (myfloat){vlen(xmult(subt(p,l.a),subt(l.b,l.a))) , distance(l.a,l.b)};
}

myfloat linetoline(line3 u,line3 v){
    point3 n=xmult(subt(u.a,u.b),subt(v.a,v.b));
    return (myfloat){dmult(subt(u.a,v.a),n)*dmult(subt(u.a,v.a),n),vlen(n)};
}
/*
int parallel(line3 u,line3 v){
    return vlen(xmult(subt(u.a,u.b),subt(v.a,v.b)))==0;
}
*/
void input(ll &x){
    scanf("%lld",&x);
}

void output(myfloat x){
    ll s[35];
    for(int i=0; i<=32; i++){
        s[i]=x.p/x.q;
        x.p%=x.q;
        x.p*=10;
    }
    s[31]+=5;
    for(int i=31; i>0; i--){
        if(s[i]>9){
            s[i]-=10;
            s[i-1]++;
        }
        else
            break;
    }
    printf("%lld.",s[0]);
    for(int i=1; i<=30; i++){
        printf("%lld",s[i]);
    }
    printf("\n");
    return;
}

int getd(point3 x, line3 u){
    if(dmult(subt(x,u.a),subt(u.b,u.a))<0)
        return -1;
    if(dmult(subt(x,u.b),subt(u.a,u.b))<0)
        return 1;
    return 0;
}

myfloat ptoseg(point3 x, line3 u){
    if(u.a.x==u.b.x && u.a.y==u.b.y && u.a.z==u.b.z)
        return (myfloat){dis(x,u.a),1};
    if(getd(x,u)>0)
        return (myfloat){dis(x,u.b),1};
    if(getd(x,u)<0)
        return (myfloat){dis(x,u.a),1};
    return ptoline(x,u);
}

int t;
int main(){
    scanf("%d",&t);
    for(int tt=1; tt<=t; tt++){
        line3 a,b;
        input(a.a.x);
        input(a.a.y);
        input(a.a.z);
        input(a.b.x);
        input(a.b.y);
        input(a.b.z);
        input(b.a.x);
        input(b.a.y);
        input(b.a.z);
        input(b.b.x);
        input(b.b.y);
        input(b.b.z);
        myfloat ans=(myfloat){inf,1};
        point3 n=xmult(subt(a.a,a.b),subt(b.a,b.b));
        point3 p1=xmult(subt(a.b,a.a),n),p2=xmult(subt(b.b,b.a),n);
        if(dmult(subt(b.a,a.a),p1)*dmult(subt(b.b,a.a),p1)<0 && (dmult(subt(a.a,b.a),p2)*dmult(subt(a.b,b.a),p2))<0){
            if(vlen(n)!=0)
                ans=linetoline(a,b);
            else ans=(myfloat){0,1};
            //cout<<ans.p<<" "<<ans.q<<endl;
            //output(ans);
        }
        ans=min(ans,ptoseg(a.a,b));
        ans=min(ans,ptoseg(a.b,b));
        ans=min(ans,ptoseg(b.a,a));
        ans=min(ans,ptoseg(b.b,a));
        output(ans);
    }
    return 0;
}

D
正弦定理xjb迭代下。

#include<bits/stdc++.h>
using namespace std;

const double pi=acos(-1);

int t,n;
double l,s,xs,theta,delta;

inline double getarea(double l){
    return 0.5*n*sin(theta)*(l/2.0/sin(theta/2.0))*(l/2.0/sin(theta/2.0));
}

int main(){
    scanf("%d",&t);
    for(int tt=1; tt<=t; tt++){
        scanf("%d%lf%lf",&n,&l,&s);
        theta=2.0*pi/n;
        delta=pi-theta;
        xs=sin(delta)/(2.0*sin(theta/2.0));
        double tmpl=l;
        int ans=0;
        while(getarea(tmpl)>s){
            tmpl*=xs;
            ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}

E
倍长字符串,发现最终的回文串在倍长的字符串上是连续的一段。问题就变成了求修改两个以内字符的最长回文子串。先hash一下,枚举中心,做一次二分,把边界上坏的改了,继续二分,再把边界上坏的改了,再二分下,就完了。时限比较紧,要自然溢出。

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
int T;
char s[200003];
ll pw[200003];
ll h1[200003];
ll h2[200003];
ll gethash1(int l,int r){
    return h1[r]-h1[l-1]*pw[r-l+1];
}
ll gethash2(int l,int r){
    return h2[l]-h2[r+1]*pw[r-l+1];
}
int main(){
    scanf("%d",&T);
    pw[0]=1;
    for(int i=1;i<=200000;i++)pw[i]=pw[i-1]*131;
    while(T--){
        scanf("%s",s+1);
        int n=strlen(s+1);
        for(int i=1;i<=n;i++)s[i+n]=s[i];
        h1[0]=0;
        for(int i=1;i<=2*n;i++)h1[i]=s[i]-'a'+1+h1[i-1]*131;
        h2[2*n+1]=0;
        for(int i=2*n;i>=1;i--)h2[i]=s[i]-'a'+1+h2[i+1]*131;

        int ans=1;
        for(int i=1;i<=2*n;i++){
            int l=1,r=min(i,2*n-i+1),tag=-1;
            while(1){
                if(r-l<=1){
                    if(gethash1(i-r+1,i)==gethash2(i,i+r-1))tag=r;
                    else tag=l;
                    break;
                }
                int mid=(l+r)/2;
                if(gethash1(i-mid+1,i)==gethash2(i,i+mid-1))l=mid;
                else r=mid;
            }
            int bd=tag+2;
            l=bd-1,r=min(i,2*n-i+1);
            if(l>r){
                ans=max(ans,2*r-1);
                continue;
            }
            while(1){
                if(r-l<=1){
                    if(gethash1(i-r+1,i-bd+1)==gethash2(i+bd-1,i+r-1))tag=r;
                    else tag=l;
                    break;
                }
                int mid=(l+r)/2;
                if(gethash1(i-mid+1,i-bd+1)==gethash2(i+bd-1,i+mid-1))l=mid;
                else r=mid;
            }
            bd=tag+2;
            l=bd-1,r=min(i,2*n-i+1);
            if(l>r){
                ans=max(ans,2*r-1);
                continue;
            }
            while(1){
                if(r-l<=1){
                    if(gethash1(i-r+1,i-bd+1)==gethash2(i+bd-1,i+r-1))tag=r;
                    else tag=l;
                    break;
                }
                int mid=(l+r)/2;
                if(gethash1(i-mid+1,i-bd+1)==gethash2(i+bd-1,i+mid-1))l=mid;
                else r=mid;
            }
            ans=max(ans,2*tag-1);
        }
        if(ans>n)ans=n;
        if(ans%2==0)ans--;
        printf("%d\n",ans);
    }
}

F
枚举x的坐标,每个圆覆盖一段区间,区间求并。

#include <bits/stdc++.h>
using namespace std;
const int N=20001;
const int Q=201;
int n,m,q,T,x,y,r;
struct seg{
    int l,r;
};
bool operator<(const seg& a,const seg& b){
    if(a.l!=b.l)
        return a.l<b.l;
    return a.r<b.r;
}
vector<seg>g[N];

int main(){
    scanf("%d",&T);
    for(int tt=1;tt<=T;tt++){
        scanf("%d%d%d",&n,&m,&q);
        for(int i=0; i<n; i++){
            g[i].clear();
        }
        for(int j=1; j<=q; j++){
            scanf("%d%d%d",&x,&y,&r);
            int u,d,len;
            for(int i=max(0,x-r); i<=min(n-1,x+r); i++){
                len=sqrt(r*r-(x-i)*(x-i));
                d=max(y-len,0);
                u=min(y+len,m-1);
                //cout<<i<<" "<<d<<" "<<u<<endl;
                g[i].push_back((seg){d,u});
            }
        }
        int ans=0;
        for(int i=0; i<n; i++){
            int siz=g[i].size();
            sort(g[i].begin(),g[i].end());
            int r=-1;
            for(int j=0; j<siz; j++){
                if(g[i][j].r<=r) continue;
                if(g[i][j].l>r){
                    ans+=g[i][j].r-g[i][j].l+1;
                }
                else{
                    ans+=g[i][j].r-r;
                }
                r=g[i][j].r;
            }
        }
        printf("%d\n",n*m-ans);
    }
}

H
打表发现所有的数要么是在环上,要么是在去环的路上,所有的环都是6的因子。不在环上的暴力更新,在环上的用lazy标记处理。

#include <bits/stdc++.h>
using namespace std;
const int maxn=50003;
int a[2018];
bool vis[2018];
int temp[6];
int v[maxn];
int rd[maxn<<2];
int sum[maxn<<2];
int sumr[maxn<<2][6];
int n;
inline void pushup(int u){
    sum[u]=sum[2*u]+sum[2*u+1];
    if(rd[2*u]==-1||rd[2*u+1]==-1){
        rd[u]=-1;
        return;
    }
    rd[u]=0;
    for(int i=0;i<6;i++)sumr[u][i]=0;
    for(int i=0;i<6;i++)sumr[u][i]+=sumr[2*u][(rd[2*u]+i)%6];
    for(int i=0;i<6;i++)sumr[u][i]+=sumr[2*u+1][(rd[2*u+1]+i)%6];
}
inline void pushdown(int u){
    if(rd[u]<=0)return;
    rd[2*u]=(rd[2*u]+rd[u])%6;
    sum[2*u]=sumr[2*u][rd[2*u]];
    rd[2*u+1]=(rd[2*u+1]+rd[u])%6;
    sum[2*u+1]=sumr[2*u+1][rd[2*u+1]];
    for(int i=0;i<6;i++)temp[i]=sumr[u][(rd[u]+i)%6];
    for(int i=0;i<6;i++)sumr[u][i]=temp[i];
    rd[u]=0;

}
void build(int u,int l,int r){
    if(l==r){
        sum[u]=v[l];
        if(vis[sum[u]]){
            rd[u]=0;
            sumr[u][0]=sum[u];
            for(int i=1;i<6;i++){
                sumr[u][i]=sumr[u][i-1]*sumr[u][i-1]%2018;
            }
        }
        else {
            rd[u]=-1;
        }
        return;
    }
    int mid=(l+r)/2;
    build(2*u,l,mid);
    build(2*u+1,mid+1,r);
    pushup(u);
}
void update(int u,int l,int r,int ql,int qr){
    if(ql>r||qr<l)return;
    if(ql<=l&&r<=qr&&rd[u]!=-1){
        rd[u]=(rd[u]+1)%6;
        sum[u]=sumr[u][rd[u]];
        return;
    }
    if(l==r){
        sum[u]=sum[u]*sum[u]%2018;
        if(vis[sum[u]]){
            rd[u]=0;
            sumr[u][0]=sum[u];
            for(int i=1;i<6;i++){
                sumr[u][i]=sumr[u][i-1]*sumr[u][i-1]%2018;
            }
        }
        else {
            rd[u]=-1;
        }
        return ;
    }
    int mid=(l+r)/2;
    pushdown(u);
    update(2*u,l,mid,ql,qr);
    update(2*u+1,mid+1,r,ql,qr);
    pushup(u);
}
int query(int u,int l,int r,int ql,int qr){
    if(ql>r||qr<l)return 0;
    if(ql<=l&&r<=qr)return sum[u];
    int mid=(l+r)/2;
    pushdown(u);
    int ret=0;
    ret+=query(2*u,l,mid,ql,qr);
    ret+=query(2*u+1,mid+1,r,ql,qr);
    return ret;
}

int main(){
    int cnt=0;
    for(int i=0;i<2018;i++){
        memset(a,-1,sizeof(a));
        int tmp=i;
        for(int j=0;;j++){
            if(a[tmp]==-1)a[tmp]=j;
            else {
                if(tmp==i)vis[i]=true;
                else cnt;
                break;
            }
            tmp=tmp*tmp%2018;
        }
    }
    /*for(int i=0;i<2018;i++)if(vis[i]){
        int p=i;
        for(int j=1;j<=6;j++){
            p=p*p%2018;
        }
        if(p!=i)cout<<"sb\n";
    }*/
    int T;
    scanf("%d",&T);
    for(int tt=1;tt<=T;tt++){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&v[i]);
        build(1,1,n);
        printf("Case #%d:\n",tt);
        int q;
        scanf("%d",&q);
        while(q--){
            char op[3];
            int l,r;
            scanf("%s%d%d",op,&l,&r);
            if(op[0]=='C')update(1,1,n,l,r);
            else printf("%d\n",query(1,1,n,l,r));
        }
    }
}

J
枚举SOD,数位dp一下。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[14][109][109][109];
int dig[14];
int add[14][109];
ll n;
int tot;
ll dfs(int pos,int mod,int sum,int status,int limit){
    if(pos<1){
        if(sum==mod&&status==0)return 1;
        else return 0;
    }
    if(sum>mod)return 0;
    if(!limit&&dp[pos][mod][sum][status]!=-1){
        return dp[pos][mod][sum][status];
    }
    int end=limit?dig[pos]:9;
    ll ret=0;
    for(int i=0;i<=end;i++){
        ret+=dfs(pos-1,mod,sum+i,(status+add[pos][mod]*i)%mod,limit&&(i==end));
    }
    if(!limit)dp[pos][mod][sum][status]=ret;
    return ret;
}
int main(){
    int T;
    scanf("%d",&T);
    memset(dp,-1,sizeof(dp));
    for(int i=1;i<=108;i++){
        int tmp=1;
        for(int j=1;j<=13;j++){
            add[j][i]=tmp;
            tmp=tmp*10%i;
        }
    }
    for(int tt=1;tt<=T;tt++){
        scanf("%lld",&n);
        ll ans=0;
        if(n==1000000000000ll){
            n--;
            ans++;
        }
        tot=0;
        while(n){
            dig[++tot]=n%10;
            n/=10;
        }
        for(int i=1;i<=tot*9;i++)ans+=dfs(tot,i,0,0,1);
        printf("Case %d: %lld\n",tt,ans);
    }
}

K
签到。

#include<bits/stdc++.h>
using namespace std;
const int N=30;
int t;
int a[N][N],b[N][N],c[N][N];
int m,n,p,q;

int main(){
    scanf("%d",&t);
    for(int tt=1; tt<=t; tt++){
        memset(c,0,sizeof(c));
        scanf("%d%d%d%d",&n,&m,&p,&q);
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++)
                scanf("%d",&a[i][j]);
        for(int i=0; i<p; i++)
            for(int j=0; j<q; j++)
                scanf("%d",&b[i][j]);
        if(m!=p){
            printf("Case %d:\nERROR\n",tt);
        }
        else{
            for(int i=0; i<n; i++){
                for(int j=0; j<q; j++){
                    for(int k=0; k<m; k++)
                        c[i][j]+=a[i][k]*b[k][j];
                }
            }
            printf("Case %d:\n",tt);
            for(int i=0; i<n; i++){
                for(int j=0; j<q; j++)
                    printf("%d%c",c[i][j],j==q-1?'\n':' ');
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值