zoukankan      html  css  js  c++  java
  • 2019CCPC-江西省赛(重现赛)- 感谢南昌大学

    A题:

    题意: 给你两棵树,然后用一条边将这两棵树连接起来,然后计算 每两点之间的距离,然后求和,问这个和的最小值。

    思路:根据重心的性质,树上的所有点到重心的距离最短,因此我们找到两棵树的重心,然后将其连起来。两点之间距离与其边的条数有关,因此我们只需要计算每一条边用过的次数就行了,即该上方的点乘以该边下方的点就是这条边被用过的次数。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1E5+7;
    const int INF=1E9+7;
    vector <ll>ve[N];
    bool mark[N];
    ll n;
    ll sz[N];
    ll aaans=0;
    ll sumt1=1;
    ll pos=1;
    void dfs1(ll x){//第一遍DFS,用来求第一棵树点的个数
        mark[x]=1;
        for(ll i=0;i<ve[x].size();i++){
            if(mark[ve[x][i]]) continue ;
            sumt1++;
            dfs1(ve[x][i]);
        }
    }
    ll dfs2(ll x,ll n1,ll &ans,ll &pos){//第二个DFS用来找树的重心
        mark[x]=1;
        ll sum=0;
        ll s=0;
        for(ll i=0;i<ve[x].size();i++){
            if(mark[ve[x][i]]) continue;
            ll x1=dfs2(ve[x][i],n1,ans,pos);
            s=max(s,x1);
            sum+=x1;
        }
        s=max(s,n1-sum-1);    
        if(s<ans){
            ans=s;
            pos=x;
        }
        return sum+1;
    }
    
    ll dfs3(ll x){// 用来计算边用过的次数
        mark[x]=1;
        ll sum=1;
        for(int i=0;i<ve[x].size();i++){
            if(mark[ve[x][i]]) continue ;
            int x1=dfs3(ve[x][i]);
            sum+=x1;
        }
        aaans+=sum*(n-sum);//sum 是当前点以下所有的点的个数,n-sum是当前点以上所有点的个数
        return sum;
    }
    int main(){
        cin>>n;
        ll x,y;
        for(ll i=1;i<=n-2;i++){
            cin>>x>>y;
            ve[x].push_back(y);
            ve[y].push_back(x);
        }
        dfs1(1);
        ll sumt2=n-sumt1;
        ll ans1=INF,pos1;
        memset(mark,0,sizeof mark);
        dfs2(1,sumt1,ans1,pos1);
        ll ans2=INF,pos2;
        for(ll i=1;i<=n;i++) {
            if(!mark[i]){
                dfs2(i,sumt2,ans2,pos2);
                break;
            }
         }
        ve[pos1].push_back(pos2);
         ve[pos2].push_back(pos1);
         memset(mark,0,sizeof mark);
        dfs3(1);
        cout<<aaans<<endl;
        return 0;
    }

    D题:

    题目大意:在一组数列中选择两个数,使其可以构成"wave"的最大长度,比如说对于数列1 2 1  3  2

    选择12的话,不要看3,这两个数字可以构成的“”wave“”最大长度为4,对于数列1 2  1 1 2 可以构成的最大长度也是4 ,对于选择好的数,我们可以选择性的保留,也就是说我们可以舍弃一个1..(没读懂题意,wa了好几发)

    思路:记录每个数字出现的位置,然后暴力枚举每一种情况,然后取最大。(听说正解是dp)

    ACcode

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1E2+7;
    vector<int >ve[N];
    
    int check(int a,int b){
        int i=1,ja=0,jb=0,j=-1;
        int aa=ve[a].size();
        int bb=ve[b].size();
        int ans=0;
        while(1){
            if(i&1){
                while(ja<aa&&ve[a][ja]<j){
                    ja++;
                }
                if(ja==aa) break;
                j=ve[a][ja];
                ans++;
            }
            else {
                while(jb<bb&&ve[b][jb]<j){
                    jb++;
                }
                if(jb==bb) break;
                j=ve[b][jb];
                ans++;
            }
            i++;
        }
        return ans;
    }
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        int a;
        for(int i=1;i<=n;i++){
            scanf("%d",&a);
            ve[a].push_back(i);
        }
        int ans=0;
        
        for(int i=1;i<=m;i++){
            if(ve[i].size()==0) continue ;
            for(int j=1;j<=m;j++){
                if(ve[j].size()==0||i==j) continue ;
                ans=max(ans,check(i,j));
            }
        }
        printf("%d
    ",ans);
        return 0;
    }

    https://blog.csdn.net/qq_41646772/article/details/96831855

    dp解法,用一个二维数组,记录i到j的长度,从i到j的长度等以从j到i的长度+1,即dp[i][j]=d[j][i]+1

    dpcode

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1E2+7;
    int dp[N][N];
    int main(){
        int n,m;
        cin>>n>>m;
        int ans=0;
        int x;
        for(int i=1;i<=n;i++){
            cin>>x;
            for(int j=1;j<=m;j++){
                dp[j][x]=dp[x][j]+1;
                if(j==x) continue ;
                ans=max(ans,dp[j][x]);
            }
        }
        cout<<ans<<endl;
        return 0;
    }

    F题  记录每个字符出现的次数计即可

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1000;
    char arr[N];
    int a,v,i,n;
    
    int main(){
        int m;
        while(scanf("%d",&m)!=EOF){
            a=0,v=0,i=0,n=0;
            scanf("%s",arr+1);
            int l=strlen(arr+1);
            
            for(int j=1;j<=l;j++){
                if(arr[j]=='a') a++;
                if(arr[j]=='v') v++;
                if(arr[j]=='i') i++;
                if(arr[j]=='n') n++;
            }
            
            int x=a*v*i*n;
            int s=pow(m,4);
            if(x==0){
                cout<<0<<"/"<<1<<endl;
            }
            else {
                cout<<x/__gcd(x,s)<<"/"<<s/__gcd(x,s)<<endl;
            }
        }
        return 0;
    }

    G题 

    一开始诶读懂题意,以为是能过就过,不能过的话在南北方向的车等待。然而不是,题意是一起等待。。。(无聊至极)

    二分水过

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1E3+7;
    int arr[N];
    int brr[N];
    int n,m;
    bool check(int s){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(arr[i]==brr[j]+s) return false;
                if(arr[i]<brr[j]+s) break;
            }
        }
        return true;
    }
    int main(){
        while(scanf("%d%d",&n,&m)!=EOF){
            for(int i=1;i<=n;i++)    scanf("%d",&arr[i]);    
            for(int i=1;i<=m;i++)    scanf("%d",&brr[i]);
            sort(arr+1,arr+1+n);
            sort(brr+1,brr+1+m);
            int l=0,r=2000;
            int ans=1000000;
            while(l<=r){
                int mid=(l+r)/2;
                if(check(mid)){
                    ans=min(mid,ans);
                    r=mid-1;
                }
                else {
                    l=mid+1;
                }
            }
            printf("%d
    ",ans);
        }    
        return 0;
    }

    H-RNG

    打表找规律吧,,一定能找到的。。。。。

    2/2 ,,3/4,,,4/6,,,5/8

    //2/2  3/4  4/6  5/8
    //   1    2    3   4
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long l
    const ll mod=1e9+7;
    ll ksm(ll n,ll m){
        ll res=1;
        while(m){
            if(m&1) res=res*n%mod;
            m>>=1;
            n=n*n%mod;
        }
        return res%mod;
    }
    
    
    int main(){
        ll n;
        while(~scanf("%dll",&n)){
            ll a=n+(ll)1 ;
            cout<<a*ksm((ll)2*n,mod-2)%mod<<endl;
        }
        return 0;
    }

    I--

    被这个题目卡了好久,用long double输入不对,最后用字符串输入的。。。直接保留小数点后三位就可以了,其余的不用管。

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=100;
    char arr[N];
    int main(){
        int t;
        while(scanf("%d",&t)!=EOF){
            int c=0;
            for(int i=1;i<=t;i++){
                scanf("%s",arr);
                int s=strlen(arr);
                int ans=0;
                
                for(int j=s-1;;j--){
                    if(arr[j]=='.'){
                        for(int k=j+1;k<s;k++){
                            ans*=10;
                            ans+=arr[k]-'0';
                        }
                        break;
                    }
                }
                int sum=0;
                int x=ans%10;
                if(x>=0&&x<=4){
                    sum=ans-x;
                }
                else {
                    sum=ans-x+10;    
                }
                c+=sum-ans;        
            }
            float q=1000;
            printf("%.3f
    ",c/q);
        }
        return 0;
    }

    J-worker 

    每个仓库完成的额度相同,所以想到的lcm,,,然后二分就可以了,注意l和r的取值,l最小为lcm*1,,r最大为m/lcm

    注意输出格式,PE了一发

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1000+7;
    ll arr[N];
    ll mark[N];
    ll n,m;
    
    ll check(ll s){
        ll sum=0;
        for(ll i=1;i<=n;i++){
            sum+=s/arr[i]; 
            mark[i]=s/arr[i];
        }
        if(sum==m) return 1;
        if(sum>m) return 0;
        else return 2;
    }
    
    int main(){
        while(~scanf("%lld%lld",&n,&m)){
            for(ll i=1;i<=n;i++)    scanf("%lld",&arr[i]);
            ll base=arr[1];
            
            for(ll i=2;i<=n;i++){
                base=base*arr[i]/__gcd(base,arr[i]);
            }
            
            ll l=1,r=m/base;
            bool flag=false ;
            
            while(l<=r){
                ll mid=(l+r)/2;
                ll x=check(mid*base);
                if(x==1){
                    puts("Yes");
                    flag=true;
                    for(ll i=1;i<=n;i++){
                        if(i==1)    printf("%lld",mark[i]);
                        else printf(" %lld",mark[i]);
                    }
                    puts("");
                    break;
                }
                else{
                    if(x==0){//人数不够 
                        r=mid-1;
                    }
                    else if(x==2) {//人数太多 
                        l=mid+1;
                    }
                }
                
            }
            if(!flag) puts("No");
        }
        return 0;
    }
  • 相关阅读:
    入门MyBatis框架你一点都不需要慌
    手把手教你玩转Git
    小米商城项目(JSP+Servlet项目)
    超详细Maven技术应用指南
    如何深入理解关系型数据库的三大范式
    MySQL触发器的详细教学与实战分析
    cute-cnblogs 番外篇-自定义博客园样式美化
    2019以终为始,不迷茫的2020 | 前端小菜鸡的年度总结~
    可爱的博客园样式之自定义“评论区”样式
    Vue中使用key的作用
  • 原文地址:https://www.cnblogs.com/Accepting/p/11837966.html
Copyright © 2011-2022 走看看