zoukankan      html  css  js  c++  java
  • PTA天梯训练赛一&二

    训练赛一

    7-5 连续因子 (20 分)

    思路:
    暴力枚举起点,每次从起点往后延伸,并且更新长度和起点,最后输出即可。
    代码:

    int main(){
        ll n;scanf("%lld",&n);
        ll res=0,pos=-1;
        for(ll i=2;i*i<=n+1;i++){
            ll tmp=0;
            ll tmpn=n,t=i;
            for(;tmpn%t==0;t++,tmp++)
                tmpn/=t;
            if(res<tmp){
                res=tmp;
                pos=i;
            }
        }
        if(res==0){
            cout<<"1"<<"
    "<<n<<"
    ";
            return 0;
        }
        cout<<res<<endl;
        for(int i=1;i<=res;i++){
            cout<<pos+i-1;
            if(i!=res) cout<<"*";
        }
        puts("");
        return 0;
    }
    

    7-6 链表去重 (25 分)

    思路:
    之前存图的时候用链式前向星,这里也可以借助数组模拟链表,然而我写的暴力只过了15分。
    代码:

    const int maxn=1e5+100;
    bool vis[maxn];
    int w[maxn],ne[maxn],del_w[maxn],del_ne[maxn];
    int n,head=-1,pre=-1,del_head=-1,del_tail=-1;
    
    int main(){
        head=read,n=read;
        for(int i=1;i<=n;i++){
            int pos=read;
            w[pos]=read;ne[pos]=read;
        }
        for(int i=head;~i;i=ne[i]){
            if(vis[abs(w[i])]){
                if(pre==-1) head=ne[i];
                else ne[pre]=ne[i];
                if(del_head==-1) del_head=i;
                del_w[i]=w[i];
                if(del_tail!=-1) del_ne[del_tail]=i;
                del_tail=i;
            }
            else{
                vis[abs(w[i])]=1;
                pre=i;
            }
        }
        del_ne[del_tail]=-1;
        for(int i=head;~i;i=ne[i]){
            printf("%05d %d ",i,w[i]);
            if(ne[i]==-1) puts("-1");
            else printf("%05d
    ",ne[i]);
        }
        for(int i=del_head;~i;i=del_ne[i]){
            printf("%05d %d ",i,del_w[i]);
            if(del_ne[i]==-1) puts("-1");
            else printf("%05d
    ",del_ne[i]);
        }
        return 0;
    }
    

    7-8 凑零钱 (30 分)

    思路:
    背包dp判断能否构成的同时记录路径,输出答案的时候倒着输出。
    dfs也能过。
    代码:

    const int maxn=1e4+100;
    int n,m,a[maxn],dp[maxn];
    int vis[maxn][maxn];
    bool cmp(int a,int b){
        return a>b;
    }
    int main(){
        cin>>n>>m;
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+1+n,cmp);
        for(int i=1;i<=n;i++)
            for(int j=m;j>=0;j--){
                if(j>=a[i]){
                    if(dp[j]<=dp[j-a[i]]+a[i]){
                        dp[j]=dp[j-a[i]]+a[i];
                        vis[i][j]=1;
                    }
                }
            }
        if(dp[m]!=m) puts("No Solution");
        else{
            int tmpm=m;
            while(tmpm){
                if(vis[n][tmpm]){
                    cout<<a[n];
                    tmpm-=a[n];
                    if(tmpm>0) cout<<" ";
                }
                n--;
            }
        }
        return 0;
    }
    

    7-9 特殊堆栈 (30 分)

    思路:
    有点思维的题。在动态求中位数时,一般都是用对顶堆维护。但是对顶堆的删除操作不容易实现。
    先考虑暴力的做法,是维护一个栈和一个vector容器,每次询问时都对vector进行sort,这样复杂度是 O ( n 2 ) O(n^{2}) O(n2)
    如果在插入的时候就保持vector的有序,每次查询时都二分查找该数在有序列表中的位置,时间复杂度就降到了 O ( n l o g n + c ) O(nlogn+c) O(nlogn+c)
    代码:

    const int maxn=1e5+100;
    stack<int>stk;
    vector<int>v;
    int main(){
        int n;cin>>n;
        char op[15];
        for(int i=1;i<=n;i++){
            cin>>op;
            ///cout<<op<<endl;
            if(op[1]=='o'){
                if(v.size()==0) puts("Invalid");
                else{
                    int x=stk.top();
                    stk.pop();
                    cout<<x<<endl;
                    auto pos=lower_bound(v.begin(),v.end(),x);
                    v.erase(pos);
                }
            }
            else if(op[1]=='u'){
                int x;cin>>x;
                stk.push(x);
                auto pos=lower_bound(v.begin(),v.end(),x);
                v.insert(pos,x);
            }
            else if(op[1]=='e') {
                if(v.size()==0) puts("Invalid");
                else{
                    int t=(v.size()+1)/2-1;
                    cout<<v[t]<<endl;
                }
            }
            cout<<i<<" "<<op<<endl;
        }
        return 0;
    }
    

    7-11 肿瘤诊断 (30 分)

    思路:
    三维的bfs,有点离谱,注意判断每个连通块的最低1的个数。
    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    struct node{
        int x,y,z;
    };
    int a[60][1300][130],n,m,l,t,b[60][1300][130],res=0;
    bool check(int x,int y,int z){
        if(x>=0&&x<l&&y>=0&&y<m&&z>=0&&z<n&&a[x][y][z]==1&&b[x][y][z]==0)
            return 1;
        return 0;
    }
    int nx[]={1,-1,0,0,0,0};
    int ny[]={0,0,1,-1,0,0};
    int nz[]={0,0,0,0,1,-1};
    void bfs(int x,int y,int z){
        queue<node>q;
        q.push({x,y,z});
        b[x][y][z]=1;
        int tmp=0;
        while(!q.empty()){
            node t=q.front();q.pop();
            tmp++;
            int tx=t.x,ty=t.y,tz=t.z;
            for(int i=0;i<6;i++){
                int xx=tx+nx[i],yy=ty+ny[i],zz=tz+nz[i];
                if(check(xx,yy,zz)){
                    b[xx][yy][zz]=1;
                    q.push({xx,yy,zz});
                }
            }
        }
        if(tmp>=t) res+=tmp;
    }
    int main(){
        cin>>m>>n>>l>>t;
        for(int i=0;i<l;i++)
            for(int j=0;j<m;j++)
                for(int k=0;k<n;k++)
                    cin>>a[i][j][k];
        for(int i=0;i<l;i++)
            for(int j=0;j<m;j++)
                for(int k=0;k<n;k++)
                    if(a[i][j][k]==1&&!b[i][j][k])
                        bfs(i,j,k);
        cout<<res<<endl;
        return 0;
    }
    

    训练赛二

    7-4 天梯地图 (30 分)

    思路:
    跑两次最短路。
    对于时间来说,时间最短为第一关键字,距离最短为第二关键字。
    对于距离来说,距离最短为第一关键字,节点最少为第二关键字。
    用pre数组记录一下这个点是从哪个点转移过来的,输出的时候倒着推回去。
    判断两个路径是否相同,先判断节点个数,在枚举节点判断对应的是否相等。
    n只有500,写个朴素的dijkstra就好了
    也不知道被卡哪了。
    代码:

    const int maxn=1e6+7,inf=0x3f3f3f3f;
    int n,m,g1[510][510],g2[510][510],s,e;
    int dis1[maxn],st1[maxn],pre1[maxn],cnt[maxn];
    int dis2[maxn],st2[maxn],pre2[maxn],d[maxn];
    void dijkstra1(){
        memset(dis1,0x3f,sizeof dis1);
        dis1[s]=0;
        pre1[s]=-1;
        for(int i=1;i<=n;i++) cnt[i]=1;
        for(int i=0;i<n-1;i++){
            int t=-1;
            for(int j=1;j<=n;j++)
                if(!st1[j]&&(t==-1||dis1[t]>dis1[j]))
                    t=j;
            for(int j=1;j<=n;j++){
                if(dis1[j]>dis1[t]+g1[t][j]){
                    dis1[j]=dis1[t]+g1[t][j];
                    pre1[j]=t;
                    cnt[j]=cnt[t]+1;
                }
                else if(dis1[j]==dis1[t]+g1[t][j]){
                    if(cnt[j]>cnt[t]+1){
                        pre1[j]=t;
                        cnt[j]=cnt[t]+1;
                    }
                }
            }
            st1[t]=1;
        }
    }
    void dijkstra2(){
        memset(dis2,0x3f,sizeof dis2);
        memset(d,0x3f,sizeof d);
        dis2[s]=0;d[s]=0;
        pre2[s]=-1;
        for(int i=0;i<n-1;i++){
            int t=-1;
            for(int j=1;j<=n;j++)
                if(!st2[j]&&(t==-1||dis2[t]>dis2[j]))
                    t=j;
            for(int j=1;j<=n;j++){
                if(dis2[j]>dis2[t]+g2[t][j]){
                    dis2[j]=dis2[t]+g2[t][j];
                    pre2[j]=t;
                    d[j]=d[t]+g1[t][j];
                }
                else if(dis2[j]==dis2[t]+g2[t][j]){
                    if(d[j]>d[t]+g1[t][j]){
                        pre1[j]=t;
                        d[j]=d[t]+g1[t][j];
                    }
                }
            }
            st2[t]=1;
        }
    }
    int main(){
        n=read,m=read;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(i==j) g1[i][j]=g2[i][j]=0;
                else g1[i][j]=g2[i][j]=inf;
        rep(i,1,m){
            int u=read,v=read,op=read,l=read,t=read;
            u++,v++;
            if(op==1){
                g1[u][v]=min(g1[u][v],l);
                g2[u][v]=min(g2[u][v],t);
            }
            else{
                g1[u][v]=min(g1[u][v],l);
                g2[u][v]=min(g2[u][v],t);
                g1[v][u]=min(g1[v][u],l);
                g2[v][u]=min(g2[v][u],t);
            }
        }
        s=read,e=read;
        s++,e++;
        dijkstra1();
        dijkstra2();
        int res_time=dis2[e],res_dis=dis1[e];
        string path_time,path_dis;
        int tmp=e;
        while(tmp!=-1){
            path_time+=(tmp-1+'0');
            tmp=pre2[tmp];
        }
        tmp=e;
        while(tmp!=-1){
            path_dis+=(tmp-1+'0');
            tmp=pre1[tmp];
        }
        reverse(path_dis.begin(), path_dis.end());
        reverse(path_time.begin(), path_time.end());
        if(path_dis==path_time){
            printf("Time = %d; Distance = %d: ",res_time,res_dis);
            for(int i=0;i<path_dis.size();i++){
                cout<<path_dis[i];
                if(i!=path_dis.size()-1) cout<<" => ";
            }
        }
        else{
            printf("Time = %d: ",res_time);
            for(int i=0;i<path_time.size();i++){
                cout<<path_time[i];
                if(i!=path_time.size()-1) cout<<" => ";
            }
            puts("");
            printf("Distance = %d: ",res_dis);
            for(int i=0;i<path_dis.size();i++){
                cout<<path_dis[i];
                if(i!=path_dis.size()-1) cout<<" => ";
            }
        }
        return 0;
    }
    
    

    7-9 家庭房产 (25 分)

    思路:
    思路不难想,就是并查集,但是有点难处理。
    每次将根节点维护为家族里编号最小的编号,剩下的就是模拟了。
    代码:

    const int maxn=11000;
    int root[maxn],siz[maxn];
    struct node{
        ll minid,siz,id;
        double cnt,area;
    }a[1100];
    int cnt_sum[maxn],cnt_area[maxn];
    bool vis[maxn];
    int Find(int x){
        if(x!=root[x]) root[x]=Find(root[x]);
        return root[x];
    }
    void Union(int x,int y){
        x=Find(x),y=Find(y);
        if(x!=y){
            if(x<y){
                root[y]=x;
                siz[x]+=siz[y];
                cnt_area[x]+=cnt_area[y];
                cnt_sum[x]+=cnt_sum[y];
            }
            else{///y的编号小
                root[x]=y;
                siz[y]+=siz[x];
                cnt_area[y]+=cnt_area[x];
                cnt_sum[y]+=cnt_sum[x];
            }
        }
    }
    bool cmp(node a,node b){
        if(a.area==b.area){
            return a.id<b.id;
        }
        return a.area>b.area;
    
    }
    int main(){
        for(int i=0;i<=9999;i++) root[i]=i,siz[i]=1;
        int n=read;
        rep(i,1,n){
            int now=read;
            vis[now]=1;
            int fa=read,mo=read;
            if(fa!=-1){
                Union(fa,now);
                vis[fa]=1;
            }
            if(mo!=-1){
                vis[mo]=1;
                Union(mo,now);
            }
            int k=read;
            rep(j,1,k){
                int son=read;
                vis[son]=1;
                Union(son,now);
            }
            int t=Find(now);
            ll t1=read,t2=read;
            cnt_sum[t]+=t1;
            cnt_area[t]+=t2;
        }
        int cnt=0;
        for(int i=0;i<=9999;i++)
            if(vis[i]&&i==Find(i)){
                a[++cnt]={i,siz[i],cnt,cnt_sum[i]*1.0/siz[i],cnt_area[i]*1.0/siz[i]};
            }
        sort(a+1,a+1+cnt,cmp);
        cout<<cnt<<endl;
        for(int i=1;i<=cnt;i++)
            printf("%04lld %lld %.3f %.3f
    ",a[i].minid,a[i].siz,a[i].cnt,a[i].area);
    	return 0;
    }
    
    

    7-10 最长对称子串 (25 分)

    思路:
    有好几种解法:
    1.马拉车,复杂度 O ( n ) O(n) O(n)
    2.二分对称子串的长度,复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
    3.枚举对称点,每次从对称点往周围延伸,记录最大长度。跟马拉车的思想类似,复杂度 O ( n 2 ) O(n^{2}) O(n2)
    4.枚举起点和终点,复杂度 O ( n 3 ) O(n^{3}) O(n3),但是跑不满,应该也能过。
    代码:

    const int maxn= 3000+10;
    char str[maxn];
    string s;
    int len1,len2,res,p[maxn];
    void init(){
        str[0]='$';str[1]='#';
        for(int i=0;i<len1;i++){
            str[i*2+2]=s[i];
            str[i*2+3]='#';
        }
        len2=len1*2+2;
        str[len2]='*';
    }
    void manacher(){
        int id=0,mx=0;
        for(int i=1;i<len2;i++){
            if(mx>i) p[i]=min(p[id*2-i],mx-i);
            else p[i]=1;
            for(;str[i+p[i]]==str[i-p[i]];p[i]++);
            if(p[i]+i>mx){
                mx=p[i]+i;
                id=i;
            }
        }
    }
    int main(){
    	getline(cin,s);
    	len1=s.size();
    	init();
    	manacher();
    	int res=0;
    	for(int i=1;i<len2;i++)
            res=max(res,p[i]);
        cout<<res-1;
    	return 0;
    }
    
    
    

    7-11 垃圾箱分布 (30 分)

    思路:
    将垃圾箱的编号调整到 [ n + 1 , n + m ] [n+1,n+m] [n+1,n+m]
    m最大为10,对每个垃圾箱都跑一遍最短路,记录最短距离,平均距离,编号,sort后输出。
    代码:

    const int maxn=1e6+7,inf=0x3f3f3f3f;
    int n,m,k,ds,g[1100][1100];
    struct node{
        int id,minn;
        double ave;
    }a[12];
    int idx;
    bool cmp(node a,node b){
        if(a.minn==b.minn){
            if(a.ave==b.ave){
                return a.id<b.id;
            }
            return a.ave<b.ave;
        }
        return a.minn>b.minn;
    }
    int dis[maxn];///记录当前点到起点的距离
    bool st[maxn];///若当前点的最短距离已经确定 为true
    
    void dfs(int s){
        memset(dis,0x3f,sizeof dis);///初始化距离为正无穷
        memset(st,0,sizeof st);
        dis[s]=0;///从1开始更新
        for(int i=0;i<n+m-1;i++){
            int t=-1;
            ///找到当前不在st中而且距离最小的点t
            for(int j=1;j<=n+m;j++)
                if(!st[j]&&(t==-1||dis[t]>dis[j]))
                    t=j;
            ///用点t更新其他不在st中的点的距离
            for(int j=1;j<=n+m;j++)
                dis[j]=min(dis[j],dis[t]+g[t][j]);
            ///将t点放到st集合里
            st[t]=true;
        }
        int res=inf,cnt=0,sum=0;
        for(int i=1;i<=n;i++){
            if(dis[i]>ds){
                break;
            }
            sum+=dis[i];cnt++;
            res=min(res,dis[i]);
        }
        if(cnt==n){
            idx++;
            a[idx]={s,res,sum*1.0/n};
        }
    
    }
    
    int main(){
        n=read,m=read,k=read,ds=read;
        for(int i=1;i<=n+m;i++)
            for(int j=1;j<=n+m;j++)
                if(i==j) g[i][j]=0;
                else g[i][j]=inf;
        for(int i=1;i<=k;i++){
            string x,y;cin>>x>>y;
            int t=read;
            int cntx=0,cnty=0;
            if(x[0]=='G'){
                for(int j=1;j<x.size();j++)
                    cntx=cntx*10+x[j]-'0';
                cntx+=n;
            }
            else{
                for(int j=0;j<x.size();j++)
                    cntx=cntx*10+x[j]-'0';
            }
            if(y[0]=='G'){
                for(int j=1;j<y.size();j++)
                    cnty=cnty*10+y[j]-'0';
                cnty+=n;
            }
            else{
                for(int j=0;j<y.size();j++)
                    cnty=cnty*10+y[j]-'0';
            }
           /// cout<<i<<"******"<<cntx<<" "<<cnty<<endl;
            g[cntx][cnty]=g[cnty][cntx]=min(t,g[cntx][cnty]);
        }
        for(int i=n+1;i<=n+m;i++)
            dfs(i);
       /// cout<<idx<<endl;
        if(idx==0) puts("No Solution");
        else{
            sort(a+1,a+1+idx,cmp);
            cout<<"G"<<a[1].id-n<<endl;
            printf("%.1lf %.1lf
    ",1.0*a[1].minn,a[1].ave);
        }
        return 0;
    }
    
    
  • 相关阅读:
    postman——集合——执行集合——测试脚本——示例09——检查响应体的json值
    和菜鸟一起深入学习国嵌实验之进程创建,exec函数,进程等待
    “万能数据库查询分析器”中文版本《DB 查询分析器》、英文版本《DB Query Analyzer》最新3.02 已经在中关村在线升级完成
    彻底删除文件(File Delete Absolutely) 最新3.01版本 也已经在中关村在线升级成功
    The 8th tip of SQL design by DB Query Analyzer
    万能数据库查询分析器使用技巧之(八)
    和菜鸟一起深入学习国嵌实验之进程间通信
    和菜鸟一起深入学习国嵌实验之网络编程
    Android窗口管理服务WindowManagerService对壁纸窗口(Wallpaper Window)的管理分析
    和菜鸟一起深入学习国嵌实验之线程编程
  • 原文地址:https://www.cnblogs.com/OvOq/p/14853013.html
Copyright © 2011-2022 走看看