• Gym .102021 .German Collegiate Programming Contest (GCPC 18) (寒假gym自训第三场)


    B .Battle Royale

    题意:给你两个点A,B,以及一个圆S,保证两个点在圆外,且其连线与圆相交,求两点间最短距离。

    思路:显然是要分别与圆相切,然后在圆弧想走,直到相交。 那么ans=与圆相交的直线距离+圆弧上的距离; 前者不难求。 后者的话有些抽象,因为不知道怎么取固定角度,但是如果想到atan2了就不难了,因为atan2求出的角度是固定了标准的,注意对用两个atan2求出来的角度求其夹角时,注意不要错过2pi;同时取min(angle,2*pi-angle)。  还不懂的,看代码。

    (camp也有类似的题

    #include<bits/stdc++.h>
    using namespace std;
    const double pi=acos(-1.0);
    double ans;
    double dist(double x1,double y1,double x2,double y2){
        return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    }
    pair<double,double> angle(double x1,double y1,double x,double y,double r)
    {
        double d=dist(x1,y1,x,y);
        ans+=(sqrt(d*d-r*r));
        double ang1=atan2(y1-y,x1-x);
        double ang2=acos(r/d);
        return make_pair(ang1+ang2,ang1-ang2); //返回圆心与切点的角度
    }
    double getlen(double A,double B,double r){
        A=fabs(A-B); if(A>=pi*2) A-=pi*2;
        return r*min(A,pi*2-A);
    }
    int main()
    {
        double x1,y1,x2,y2,x,y,r;
        scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
        scanf("%lf%lf%lf",&x,&y,&r);
        scanf("%lf%lf%lf",&x,&y,&r);
        pair<double,double> A=angle(x1,y1,x,y,r);
        pair<double,double> B=angle(x2,y2,x,y,r);
        double Cirlen=getlen(A.first,B.first,r);
        Cirlen=min(Cirlen,getlen(A.first,B.second,r));
        Cirlen=min(Cirlen,getlen(A.second,B.first,r));
        Cirlen=min(Cirlen,getlen(A.second,B.second,r));
        printf("%.10lf
    ",ans+Cirlen);
        return 0;
    }
    View Code

    E .Expired License

    题意:给定你两个最多带5位小数的double型a,b,让你用用一对素数x y表示他们的比值。

    思路:我们把a和b都乘1e5,化简验证是否是素数即可。 但是要注意精度误差,我们可以给把数加一个1e-7之后再乘1e5.

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(ll i=a;i<=b;i++)
    using namespace std;
    const int maxn=10000010;
    const double eps=1e-7;
    int p[maxn],cnt; bool vis[maxn];
    void prime()
    {
        vis[1]=1;
        rep(i,2,maxn-1){
            if(!vis[i]) p[++cnt]=i;
            rep(j,1,cnt){
                if(p[j]*i>=maxn) break;
                vis[i*p[j]]=1;
                if(!(i%p[j])) break;
            }
        }
    }
    int main()
    {
        double A,B; int C,D,T;
        scanf("%d",&T); prime();
        while(T--){
            scanf("%lf%lf",&A,&B);
            C=(int)((A+eps)*100000); D=(int)((B+eps)*100000);
            int g=__gcd(C,D);
            C/=g; D/=g;
            if(!vis[C]&&!vis[D]) printf("%d %d
    ",C,D);
            else if(C==1&&D==1) puts("2 2");
            else puts("impossible");
        }
        return 0;
    }
    View Code

    H .Hyper Illuminati

    题意:给定一个数N(<1e16),问是否存在n和s,满足1^n+2^n+3^n+...s^n=N;输出n+1,s;

    思路:如果2<=n<=53,我们发现s不会太大,我们可以把所有的都求出来;如果n>53,则有s<=2,我们可以把s=2的值都求出来。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(ll i=a;i<=b;i++)
    using namespace std;
    int main()
    {
        ll ans=0,N;
        cin>>N; //N=M;
        rep(i,2,53){ //幂位i+1
            ans=0;
            rep(j,1LL,N){
                ll tmp=1;
                rep(k,1,i){
                     if(tmp>N/j) {tmp=N+1; break;}
                     tmp*=j;
                }
                if(tmp>N) break;
                ans+=tmp;
                if(ans==N) return printf("%lld %lld
    ",i+1,j),0;
                if(ans>=N) break;
            }
        }
        rep(i,2,2){ //长度位2
            ll tmp=1;
            rep(j,1LL,N){
                tmp*=2;
                if(j>=2){
                    if(tmp+1==N) return printf("%lld %lld
    ",j+1,2),0;
                }
                if(tmp+1>=N) break;
            }
        }
        puts("impossible");
        return 0;
    }
    View Code

    D .Down the Pyramid

    题意:金字塔的每一层的位置的值=下一层的两个值之和,现在给你最倒数第二层的值a1,a2...an,问你最后一层有多少种情况,满足所哟数不小于0。

    思路:我们假设第一个位置位b0=x,那么b1=a1-x; b2=a2-b1=a2-a1+x.. 中间给限制让所有数大于等于0,则有x<=a1; x>=a1-a2; x<=a3+a2-a1 ; x>=...。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1000010;
    ll a[maxn],sum,Mn,Mx;
    int main()
    {
        int N; scanf("%d",&N);
        rep(i,1,N) scanf("%lld",&a[i]);
        Mn=0; Mx=a[1];
        rep(i,1,N){
            sum=a[i]-sum;
            if(i&1) Mx=min(Mx,sum);
            else Mn=max(Mn,-sum);
        }
        if(Mx<Mn) puts("0");
        else printf("%lld
    ",Mx-Mn+1);
        return 0;
    }
    View Code

    C .Coolest Ski Route

    题意:给定带边权有向图,让你找一个最长的链,满足买个点最多遍历一次。

    思路:记忆化搜索即可。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(ll i=a;i<=b;i++)
    using namespace std;
    const int maxn=100010;
    int dis[maxn],Laxt[maxn],Next[maxn],To[maxn],Len[maxn],cnt;
    void add(int u,int v,int L){
        Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; Len[cnt]=L;
    }
    int dfs(int u){
        if(dis[u]!=-1) return dis[u]; dis[u]=0;
        for(int i=Laxt[u];i;i=Next[i]) dis[u]=max(dis[u],dfs(To[i])+Len[i]);
        return dis[u];
    }
    int main()
    {
        int N,M,u,v,l,ans=0;
        scanf("%d%d",&N,&M);
        rep(i,1,N) dis[i]=-1;
        rep(i,1,M){
            scanf("%d%d%d",&u,&v,&l);
            add(u,v,l);
        }
        rep(i,1,N) ans=max(ans,dfs(i));
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    F .Fighting Monsters

    题意:给定N个怪兽,问是否能选处两个怪兽,使得他们相互攻击,最后活着的怪兽剩1滴血。

    思路:即是问是否寻在相邻的Fibonacci数。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1000010;
    int F[maxn+10],a[maxn+10],Laxt[maxn+10];
    int main()
    {
        int N,tot=0;
        F[0]=1; F[1]=1;
        for(int i=2;;i++){
            F[i]=F[i-1]+F[i-2];
            if(F[i]>maxn){ tot= i; break;}
        }
        scanf("%d",&N);
        rep(i,1,N) scanf("%d",&a[i]),Laxt[a[i]]=i;
        rep(i,1,N) {
            if(a[i]==1&&Laxt[1]>i) return printf("%d %d
    ",i,Laxt[1]),0;
        }
        rep(i,1,tot-1) {
            if(Laxt[F[i]]&&Laxt[F[i+1]]) return printf("%d %d
    ",Laxt[F[i]],Laxt[F[i+1]]),0;
        }
        puts("impossible");
        return 0;
    }
    View Code

    I .It's Time for a Montage

    by 罗

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=998244353;
    const int maxn=1e3+50;
    const ll inf=0x3f3f3f3f3f3f3f3fLL;
    int h[maxn];
    int v[maxn];
    int isok(int x,int n){
        for(int i=1;i<=n;i++){
            if(h[i]-v[i]+x==0)continue;
            else if(h[i]-v[i]+x>0)return true;
            else return false;
        }
        return true;
    }
    int main()
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)cin>>h[i];
        for(int i=1;i<=n;i++)cin>>v[i];
        int ans=0;
        for(int i=0;i<=1000;i++){
            if(isok(i,n)){
                cout<<i<<endl;
                return 0;
            }
        }
        return 0;
    }
    View Code

    L. Logic Puzzle

    题意:就是扫雷,让你复原雷图。

    思路:从左上到右下,关系是唯一对应的。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=110;
    int a[maxn][maxn],vis[maxn][maxn];
    int x[9]={1,1,1,-1,-1,-1,0,0,0};
    int y[9]={1,-1,0,1,-1,0,1,-1,0};
    int main()
    {
        int N,M; scanf("%d%d",&N,&M);
        rep(i,0,N+1) rep(j,0,M+1) scanf("%d",&a[i][j]);
        rep(i,0,N)
         rep(j,0,M){
            if(a[i][j]==1){
                vis[i+1][j+1]=1;
                rep(k,0,8) {
                    if(i+1+x[k]>=0&&i+1+x[k]<=N+1&&j+1+y[k]>=0&&j+1+y[k]<=M+1)
                     a[i+1+x[k]][j+1+y[k]]--;
                }
            }
            else vis[i+1][j+1]=-1;
        }
        rep(i,0,N+1) rep(j,0,M+1) {
            if(a[i][j]!=0) { return puts("impossible"),0;}
        }
        rep(i,1,N){
           rep(j,1,M) putchar(vis[i][j]==1?'X':'.');
           puts("");
        }
        return 0;
    }
    View Code

    K .Kitchen Cable Chaos

    题意:...

    思路:就是让你选几个棍子,使得(长度和+K-10)/个数不超过5,而且最大,背包即可。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define rep2(i,w,v) for(int i=w;i>=v;i--)
    using namespace std;
    const int maxn=10010;
    int dp[maxn][61],a[maxn];
    int main() {
        int N,g;
        scanf("%d%d",&N,&g);
        rep(i,1,N) scanf("%d",&a[i]);
        dp[0][0]=1;
        rep(i,1,N)
         rep2(j,N,1)
           rep2(k,maxn-1,a[i])
            dp[k][j]|=dp[k-a[i]][j-1];
        double ans=-1.0;
        rep(k,g-10,maxn-1){
          rep(j,1,N){
            if(!dp[k][j]) continue;
                double tmp=(k+10-g)*1.0/(j+1.0);
                if(tmp<=5.0) ans=max(ans,tmp);
            }
        }
        if(ans<0.0) puts("impossible");
        else printf("%.8f
    ", ans);
        return 0;
    }
    /*
    3 70 20 35 50
    */
    View Code

    M .Mountaineers

    题意:给定N*M座山,Q次询问,让你最小化从山S到山T经过的山的最高高度。

    思路:不难想到排序,然后启发式合并。 每次合并两个连通块,并且看有没有询问的S和T分别再两个连通块里。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1000010;
    int h[maxn],Laxt[maxn],Next[maxn],To[maxn],id[maxn];
    int cnt,ans[maxn],fa[maxn],N,M,Q,vis[maxn],sz[maxn];
    pair<int,int>p[maxn];
    set<int>s[maxn]; set<int>::iterator it;
    int get(int x,int y){ return (x-1)*M+y; }
    void add(int u,int v,int op)
    {
        Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; id[cnt]=op;
    }
    int find(int x){ return fa[x]; }
    void merge(int u,int v,int H)
    {
        if(sz[u]<sz[v])  swap(u,v);
        for(it=s[v].begin();it!=s[v].end();it++){
            int x=*it;
            for(int i=Laxt[x],f=-1;i;i=Next[i]) {
                if(!ans[id[i]]&&s[u].find(To[i])!=s[u].end()) {
                    ans[id[i]]=H;
    
                }
                if(ans[id[i]]){
                    if(f==-1) Laxt[x]=Next[i];
                    else Next[f]=Next[i];
                }
                f=i;
            }
        }
        for(it=s[v].begin();it!=s[v].end();it++){
            s[u].insert(*it);  fa[*it]=u;
        }
        s[v].clear();
        sz[u]+=sz[v];
    }
    int main()
    {
        scanf("%d%d%d",&N,&M,&Q);
        rep(i,1,N) rep(j,1,M){
            cnt++; fa[cnt]=cnt; scanf("%d",&h[cnt]);
            p[cnt].first=h[cnt],p[cnt].second=cnt;
            s[cnt].insert(cnt); sz[cnt]=1;
        }
        cnt=0; int x1,y1,x2,y2;
        rep(i,1,Q){
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            if(x1==x2&&y1==y2) ans[i]=h[get(x1,y2)];
            x1=get(x1,y1); x2=get(x2,y2);
            add(x1,x2,i); add(x2,x1,i);
        }
        sort(p+1,p+N*M+1);
        rep(i,1,N*M){
            int pos=p[i].second,H=p[i].first;
            vis[p[i].second]=1;
            if(pos%M!=1&&vis[pos-1]){
                int fu=find(pos),fv=find(pos-1);
                if(fu!=fv) merge(fu,fv,H);
            }
            if(pos>M&&vis[pos-M]){
                int fu=find(pos),fv=find(pos-M);
                if(fu!=fv) merge(fu,fv,H);
            }
            if(pos<=N*M-M&&vis[pos+M]){
                int fu=find(pos),fv=find(pos+M);
                if(fu!=fv) merge(fu,fv,H);
            }
            if(pos%M!=0&&vis[pos+1]){
                int fu=find(pos),fv=find(pos+1);
                if(fu!=fv) merge(fu,fv,H);
            }
        }
        rep(i,1,Q) printf("%d
    ",ans[i]);
        return 0;
    }
    View Code

    更美妙的方法:依然是建立连通关系,不过我们是建立一棵树,从小到大连通,每次把之前的连通块的根作为当前点的儿子。 最后就可以在线询问了,询问S和T的答案是LCA的点的值。 感觉有点向ST表求LCA的原理。 深度越低,最大值越大,我们我们需要求LCA。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=300010;
    int fa[maxn],cnt,ans[maxn],vis[510][510],rt;
    int f[maxn][20],dep[maxn]; vector<int>G[maxn];
    struct in{
        int x,y,id,h;
        in(){}
        in(int xx,int yy,int ii,int hh):x(xx),y(yy),id(ii),h(hh){}
        friend bool operator <(in w,in v){ return w.h<v.h; }
    }s[maxn];
    void add(int u,int v){ G[u].push_back(v); }
    int find(int x){
        if(x==fa[x]) return x; return fa[x]=find(fa[x]);
    }
    void dfs(int u,int pre){
        f[u][0]=pre; dep[u]=dep[pre]+1;
        for(int i=0;i<G[u].size();i++) dfs(G[u][i],u);
    }
    int LCA(int u,int v)
    {
        if(dep[u]<dep[v]) swap(u,v);
        for(int i=16;i>=0;i--) if(dep[f[u][i]]>=dep[v]) u=f[u][i];
        if(u==v) return u;
        for(int i=16;i>=0;i--) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
        return f[u][0];
    }
    int main()
    {
        int N,M,Q,h,x1,x2,y1,y2;
        scanf("%d%d%d",&N,&M,&Q);
        rep(i,1,N)
          rep(j,1,M){
             scanf("%d",&h); cnt++; fa[cnt]=cnt;
             ans[cnt]=h; s[cnt]=in(i,j,cnt,h);
        }
        sort(s+1,s+cnt+1);
        rep(i,1,cnt){
            x1=s[i].x; y1=s[i].y;
            if(vis[x1-1][y1]&&x1!=1&&find(s[i].id)!=find(s[i].id-M))
                add(fa[s[i].id],find(s[i].id-M)),fa[find(s[i].id-M)]=fa[s[i].id];
            if(vis[x1+1][y1]&&x1!=N&&find(s[i].id)!=find(s[i].id+M))
                add(fa[s[i].id],find(s[i].id+M)),fa[find(s[i].id+M)]=fa[s[i].id];
            if(vis[x1][y1-1]&&y1!=1&&find(s[i].id)!=find(s[i].id-1))
                add(fa[s[i].id],find(s[i].id-1)),fa[find(s[i].id-1)]=fa[s[i].id];
            if(vis[x1][y1+1]&&y1!=M&&find(s[i].id)!=find(s[i].id+1))
                add(fa[s[i].id],find(s[i].id+1)),fa[find(s[i].id+1)]=fa[s[i].id];
            vis[s[i].x][s[i].y]=1;
        }
        rt=find(1);
        dfs(rt,0);
        rep(i,1,16)
         rep(j,1,cnt) f[j][i]=f[f[j][i-1]][i-1];
        rep(i,1,Q){
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            x1=(x1-1)*M+y1; x2=(x2-1)*M+y2;
            int Lca=LCA(x1,x2);
            printf("%d
    ",ans[Lca]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    36ES6 class的类继承
    026Vue中 绑定class样式
    38ES6 class中的getter和setter设置
    025Vue中 _watch对比computed
    224Java零基础对象的创建
    35ES6 ES6构造函数继承
    37ES6 子类对父类方法的重写
    223Java零基础类的定义
    34ES6 class静态成员
    33ES6 class介绍与初体验
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10343979.html
Copyright © 2020-2023  润新知