zoukankan      html  css  js  c++  java
  • 【题解】电子科技大学第十八届 ACM 程序设计竞赛

    毫无悬念地被大一爷锤爆了,一道难题也不会,摸了个第十

    A - Rapport Test

    线段树,主席树

    B - Carving

    二分

    二分内切球半径(r),使得球心((r,r,r))到平面(frac{x}{a}+frac{y}{b}+frac{z}{c}=1)的距离为(r)

    #include <cstdio>
    #include <cmath>
    using namespace std;
    int a,b,c;
    double l,r,mid,v,k1,k2,k3,eps=1e-9;
    int main(){
        scanf("%d%d%d",&a,&b,&c);
        l=0,r=(double)a*b*c/(a*b+b*c+a*c);
        k1=a*b+b*c+a*c;
        k2=a*b*c;
        k3=sqrt(pow(a*b,2)+pow(b*c,2)+pow(a*c,2));
        while (r-l>eps){
            mid=(r+l)/2;
            if ((k2-mid*k1)/k3>mid)
                l=mid;else r=mid;
            
        }
        v=4.0/3.0*M_PI*pow(l,3);
        printf("%.2lf",v);
    }
    

    C - Rather Easy Problem

    中国剩余定理

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    ll gcd(ll a,ll b){
        return b==0?a:gcd(b,a%b);
    }
    ll ex_gcd(ll a,ll b,ll &x,ll &y){
        if(b==0){
            x=1;y=0;
            return a;
        }
        ll ans=ex_gcd(b,a%b,x,y);
        ll tmp=x;
        x=y;
        y=tmp-a/b*y;
        return ans;
    }
    ll modeqset(ll *a,ll *b,ll n){
        ll i,d,c,x,y,t;
        for(i=1;i<n;i++){
            c=b[i]-b[i-1];
            d=ex_gcd(a[i-1],a[i],x,y);
            if(c%d) return -1;
            t=a[i]/d;
            x=(x*(c/d)%t+t)%t;
            b[i]=x*a[i-1]+b[i-1];
            a[i]=a[i-1]*(a[i]/d);
        }
        return b[n-1];
    }
    int main(){
        ll a[30],b[30],m,tmp,flag,i,n,lcm=1,num;
            lcm=1;
            scanf("%lld%lld",&n,&m);
            for(i=0;i<m;i++){
                scanf("%lld",&a[i]);
                lcm=lcm/(gcd(lcm,a[i]))*a[i];
            }
            for(i=0;i<m;i++) scanf("%lld",&b[i]);
            ll res=modeqset(a,b,m);
            if(res==-1|| res>n){
                printf("0
    ");
            }else{
                num=(n-res)/lcm+1;
                if(res==0) num--;
                printf("%lld
    ",num);
            }
        return 0;
    }
    

    D - Nearest Shelter

    并查集,离散化

    考虑到实际上只有(m)个点是有意义的,所以可以先对坐标进行离散化

    再用并查集进行路径压缩,从而加快查询速度

    #include <bits/stdc++.h>
    using namespace std;
    const int N=1e5+2;
    int n,m,op,pos,fa[N],tmp[N],dis[N];
    struct L{
        int op,pos;
    }l[N];
    int find(int x){
        if (x==fa[x]) return x;
        return fa[x]=find(fa[x]);
    }
    int getid(int x){
        return lower_bound(tmp+1,tmp+m+2,x)-tmp;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m+1;i++) fa[i]=i;
        for (int i=1;i<=m;i++){
            scanf("%d%d",&l[i].op,&l[i].pos);
            tmp[i]=l[i].pos;
        }
        tmp[m+1]=n+1;
        sort(tmp+1,tmp+m+2);
        for (int i=1;i<=m;i++){
            int id=getid(l[i].pos),nextid=getid(l[i].pos+1);
            if (l[i].op==1){
                if (tmp[nextid]==l[i].pos+1)
                    fa[id]=nextid;
                dis[id]=1;
            }else{
                int x=find(id);
                if (x==m+1){
                    printf("-1
    ");
                }else{
                    if (dis[x])
                        printf("%d
    ",tmp[x]+1);
                    else
                        printf("%d
    ",tmp[x]);
                }
                
            }
        }
    }
    

    E - Didn't I Say to Make My Abilities Average in the Next Life?!

    线段树

    开两个线段树,一个维护区间最大值,另一个维护区间最小值

    取查询结果的均值即可

    #include <cstdio>
    #include <iostream>
    using namespace std;
    const int N=1e5;
    int n,m,a,op,cnt=0,q[N],qcnt=0;
    struct MaxSTree{
        struct P{
            int l,r,v,tag;
        }t[4*N];
        int v[N];
         int build(int x,int l,int r){
             t[x].l=l,t[x].r=r,t[x].tag=0;
             if (l==r) return t[x].v=v[l];
             int mid=(l+r)/2;
             return t[x].v=max(build(x*2,l,mid),build(x*2+1,mid+1,r));
         }
         void pushdown(int x){
             if (!t[x].tag) return;
             t[x*2].v+=t[x].tag;
             t[x*2+1].v+=t[x].tag;
             t[x*2].tag+=t[x].tag;
             t[x*2+1].tag+=t[x].tag;
             t[x].tag=0;
         }
         int add(int x,int l,int r,int v){
             if (l==t[x].l&&r==t[x].r){t[x].tag+=v;return t[x].v+=v;}
             pushdown(x);
             int mid=(t[x].l+t[x].r)/2;
             if (r<=mid) return t[x].v=max(t[x*2+1].v,add(x*2,l,r,v));
             else if (l>=mid+1) return t[x].v=max(t[x*2].v,add(x*2+1,l,r,v));
             else return t[x].v=max(add(x*2,l,mid,v),add(x*2+1,mid+1,r,v));
         }
         int query(int x,int l,int r){
             if (l==t[x].l&&r==t[x].r) return t[x].v;
             pushdown(x);
             int mid=(t[x].l+t[x].r)/2;
             if (r<=mid) return query(x*2,l,r);
             else if (l>=mid+1) return query(x*2+1,l,r);
             else return max(query(x*2,l,mid),query(x*2+1,mid+1,r));
         }
     }st1,st2;
    int main(){
        scanf("%d%d",&n,&m);
        for (int i=0;i<n;i++){
            scanf("%d",&op);
            if (op==1){
                scanf("%d",&a);
                st1.v[cnt]=a;
                st2.v[cnt]=-a;
                cnt++;
            }else{
               q[qcnt]=cnt;
               qcnt++;
            }
        }
        st1.build(1,0,cnt-1);
        st2.build(1,0,cnt-1);
        for (int i=0;i<qcnt;i++){
            double ans=(double)(st1.query(1,max(q[i]-m,0),q[i]-1)-st2.query(1,max(q[i]-m,0),q[i]-1))/2;
            printf("%.1lf
    ",ans);
        }
    }
    

    F - Fatdog 和他的拓扑排列

    找规律,分类讨论

    G - Fatdog Wants to Buy Games

    并查集

    容易看出答案是连通块个数减一

    另外需要考虑没有任何人玩过游戏的特殊情况,这时答案是总人数

    #include <cstdio>
    const int N=2e5+1;
    int n,m,k,u,v,fa[N],vis[N],ans=0;
    int find(int x){
        if (x==fa[x]) return x;
        return fa[x]=find(fa[x]);
    }
    int main(){
        scanf("%d%d%d",&n,&m,&k);
        for (int i=1;i<=n+m;i++) fa[i]=i;
        for (int i=1;i<=k;i++){
            scanf("%d%d",&u,&v);
            int fx=find(u),fy=find(n+v);
            if (fx!=fy) fa[fx]=fy;
        }
        for (int i=1;i<=n;i++){
            int fx=find(i);
            if (!vis[fx]){
                vis[fx]=1;
                ans++;
            }
        }
        if (k==0)
            printf("%d",n);
        else
            printf("%d",ans-1);
    }
    

    H - Moca 酱果然是天才

    概率DP

    I - 致十年以后的我,现在的你猜的是什么数?

    阶乘

    容易看出最优的询问方式是依次询问二进制的每一位,所以答案是(n)的排列数

    (n)超过(10^6+3)时,因为计算过程中有模数因子,所以答案为(0)

    #include <cstdio>
    #define ll long long
    const ll M=1e6+3;
    ll n,ans=1,k=1;
    int main(){
        scanf("%lld",&n);
        if (n>=M)
            ans=0;
        else
            for (ll i=1;i<=n;i++) ans=ans*i%M;
        printf("%lld",ans);
    }
    

    J - Kanade Loves Symmetry

    递归,树状数组

    依次处理从左到右的每个字符,只需要将同一种字符中最靠右侧的一个移动到与之相对称位置即可

    如果当前处理的字符没有剩余可以与之配对的相同字符,则交换顺序从右向左处理

    需要使用树状数组来维护每个元素在移动后的正确位置

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const ll N=1e5+1;
    deque<int> q[26];
    string s;
    ll len,cnt[26],pd=0,ans,vis[N],t[N],l,r;
    int lowbit(int x){
    	return x&(-x);
    }
    void add(int x,int v){
    	while(x<=len+1){
    		t[x]+=v;
    		x+=lowbit(x);
    	}
    }
    int query(int x){
    	int ans=0;
    	while(x){
    		ans+=t[x];
    		x-=lowbit(x);
    	}
    	return ans;
    }
    int main(){
        cin>>s;
        len=s.length();
        l=0;r=len-1;
        for (ll i=0;i<len;i++){
            ll x=s[i]-'a';
            q[x].push_back(i);
            cnt[x]++;
        }
        for (ll i=0;i<26;i++){
            if (cnt[i]%2==1) pd++;
        }
        if (pd>1){
            printf("Impossible");
            return 0;
        }
        for (ll i=0;i<len/2;i++){
            while (vis[l]) l++;
            while (vis[r]) r--;
            ll lnow=i;
            ll rnow=len-i-1;
            ll x=s[l]-'a';
            if (q[x].size()>=2){
                ll mov=q[x].back();
                ll movnow=mov-query(mov+1);
                ans+=rnow-movnow;
                q[x].pop_front();q[x].pop_back();
                add(mov+1,1);
                vis[l]=1;vis[mov]=1;
            }else{
                x=s[r]-'a';
                ll mov=q[x].front();
                ll movnow=mov-query(mov+1);
                ans+=movnow-lnow;
                q[x].pop_front();q[x].pop_back();
                add(l+1,-1);add(mov+1,1);
                vis[r]=1;vis[mov]=1;
            }
        }
        printf("%lld",ans);
    }
    

    K - Senpai and Pascal

    找规律

    从第一个二进制不同的位开始依次填写(1)即可

    #include <cstdio>
    #define ll long long
    ll a,b,c;
    ll l[63],r[63],x[63];
    int main(){
        scanf("%lld%lld",&a,&b);
        for (ll i=0;i<63;i++) if (a&(1LL<<i)) l[i]++;
        for (ll i=0;i<63;i++) if (b&(1LL<<i)) r[i]++;
        for (ll i=62;i>=0;i--){
            if (l[i]==r[i]){
                c+=(l[i]<<i);
            }else{
                c+=(1LL<<(i+1))-1;
                break;
            }
        }
        printf("%lld
    ",c);
    }
    

    L - UESTCPC Finals 2077

    最大值

    排除掉第一名做过的题目后在剩余的题目中找通过人数最多的即可

    #include <bits/stdc++.h>
    using namespace std;
    int n,a[13],b[13],ans,maxx=0;
    string f;
    int main(){
        cin>>n;
        cin>>f;
        for (int i=0;i<n;i++) b[f[i]-'A']=1;
        for (int i=0;i<13;i++) cin>>a[i];
        for (int i=0;i<13;i++){
            if (a[i]>maxx&&!b[i]){
                ans=i;
                maxx=a[i];
            }
        }
        printf("%c
    ",'A'+ans);
    }
    

    M - 查理不冲浪!

    自动机

    手写自动机进行模式匹配

    #include <bits/stdc++.h>
    using namespace std;
    const int R=10,C=1e5;
    int r,c;
    char a[R][C],ans[C];
    void dfs(int y,int x){
        a[y][x]='.';
        if (y-1>=0&&a[y-1][x]=='o') dfs(y-1,x);
        if (y+1<r&&a[y+1][x]=='o') dfs(y+1,x);
        if (x-1>=0&&a[y][x-1]=='o') dfs(y,x-1);
        if (x+1<c&&a[y][x+1]=='o') dfs(y,x+1);
    }
    int main(){
        scanf("%d%d",&r,&c);
        for (int i=0;i<r;i++){
            string f;
            cin>>f;
            for (int j=0;j<c;j++)
                a[i][j]=f[j];
        }
        for (int i=0;i<c;i++){
            for (int j=0;j<r;j++){
                if (a[j][i]=='o'){
                    if (a[j+1][i]=='o'&&a[j+2][i]=='o'&&a[j+3][i]=='o'&&a[j+4][i]=='o'){
                        if (a[j][i+1]=='.'){
                            ans[i]='1';
                        }
                        else if (a[j+2][i+1]=='.'){
                            ans[i+1]='0';
                        }
                        else if (a[j+1][i+2]=='o'){
                            ans[i+1]='8';
                        }else{
                            ans[i+1]='6';
                        }
                    }
                    else if (a[j][i+1]=='.'){
                        ans[i+1]='4';
                    }
                    else if (a[j+2][i+1]=='.'){
                        ans[i+1]='7';
                    }
                    else if (a[j+1][i]=='.'&&a[j+2][i]=='o'&&a[j+3][i]=='o'&&a[j+4][i]=='o'){
                        ans[i+1]='2';
                    }
                    else if (a[j+1][i]=='.'&&a[j+2][i]=='o'&&a[j+3][i]=='.'&&a[j+4][i]=='o'){
                        ans[i+1]='3';
                    }
                    else if (a[j+1][i]=='o'&&a[j+2][i]=='o'&&a[j+3][i]=='.'&&a[j+4][i]=='o'){
                        if (a[j+1][i+2]=='o'){
                            ans[i+1]='9';
                        }else{
                            ans[i+1]='5';
                        }
                    }
                    dfs(j,i);
                }
            }
            if (ans[i]) printf("%c",ans[i]);
        }
    }
    

    N - The Journey of Elaina

    DFS序,树状数组

    参考DFS序七个经典问题,本题目对应的问题是单点修改、子树和查询

    #include <cstdio>
    const int N=1e5+1;
    int n,f[N],p[N],q,op,c,w,t[N],cnt=0,idx1[N],idx2[N];
    int sz,head[N],vis[N];
    struct E{
        int next,to;
    }e[N*2];
    int lowbit(int x){
    	return x&(-x);
    }
    void add(int x,int v){
    	while(x<=n){
    		t[x]+=v;
    		x+=lowbit(x);
    	}
    }
    int sum(int x){
    	int ans=0;
    	while(x){
    		ans+=t[x];
    		x-=lowbit(x);
    	}
    	return ans;
    }
    void insert(int a,int b){
        sz++;
        e[sz].next=head[a];
        head[a]=sz;
        e[sz].to=b;
    }
    void dfs(int x){
        vis[x]=1;
        idx1[x]=++cnt;
        for (int i=head[x];i;i=e[i].next){
            int v=e[i].to;
            if (!vis[v]) dfs(v);
        }
        idx2[x]=cnt;
    }
    int main(){
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",&f[i]);
        for (int i=2;i<=n;i++){
            scanf("%d",&p[i]);
            insert(i,p[i]);
            insert(p[i],i);
        }
        dfs(1);
        for (int i=1;i<=n;i++){
            add(idx1[i],f[i]);
        }
        scanf("%d",&q);
        for (int i=1;i<=q;i++){
            scanf("%d",&op);
            if (op==1){
                scanf("%d%d",&c,&w);
                add(idx1[c],w-f[c]);
                f[c]=w;
            }else{
                scanf("%d",&c);
                printf("%d
    ",sum(idx2[c])-sum(idx1[c]-1));
            }
        }
    }
    

    O - Fatdog's True Love

    二分,容斥

    P - UNIX 时间戳

    差分约束

  • 相关阅读:
    「SHOI2015」脑洞治疗仪
    LOJ 数列分块入门 8
    CF932F Escape Through Leaf
    NOIP2021游记总结
    [HEOI2016/TJOI2016]序列
    【模板】动态树(Link Cut Tree)
    LG P2839 [国家集训队]middle
    JZOJ 7377.欢乐豆
    JZOJ 7392. 【2021.11.17NOIP提高组联考】数 (ds)
    LOJ 数列分块入门 6
  • 原文地址:https://www.cnblogs.com/algonote/p/14060246.html
Copyright © 2011-2022 走看看