zoukankan      html  css  js  c++  java
  • Codeforces Round #496 (Div. 3)A~F

    (寒假训练赛,也是lj难得补完的一场

    https://codeforces.com/contest/1005

    A.题意是  每一个楼梯有x个台阶,小女孩爬楼的时候会从1开始数每层楼有几个台阶,现在给给出n个数字a1~an,代表着小女孩爬楼时数数的序列,求有多少层楼梯,并且输出每层楼梯台阶数。

    解法:for循环模拟小女孩从1开始数,数到下一个1的话楼层++,然后把他前一个数存进去。

            int now = 0;
        for(int i = 0;i < n;++i){
            cin>>a;
            if(a == now+1)now++;
            else if(a == 1){
                ans[cnt++] = now;now = 1;
            }
        }
        ans[cnt++] = now;
        cout<<cnt<<endl;
        for(int i = 0;i < cnt;++i)cout<<ans[i]<<" ";

    B.题意是 给出两串序列,每次能对非空字符串的左端字符,用最少移动次数使得两个字符串相等(空串也相等

    解法:从后往前对比两个字符串的最长后缀,然后计算出删除前端的字串长度

        int l1 = s1.size(),l2= s2.size(),flag = 0;
        for(int i = l1-1,j = l2-1;i>=0,j>=0;--i,--j){
            if(s1[i]!=s2[j]){break;}
            flag++;
        } 
        cout<<l1+l2-flag*2<<endl;

    C.定义:有一个数组,每个元素都能够找到另一个元素使得两个元素之和为2的幂。如果给出的数组不满足条件则删除部分元素或者全部元素(空集符合条件),求最少删除多少数可以满足定义

    解法:这题比较灵性了,普通暴力肯定不行,一开始想的是用map映射2的幂,然后for查询依次判断和是否为2的幂,这个时候复杂度应该有n*n*logn(我也忘了最初思路是不是这样的,反正复杂度挺高的)。优化后的方法是这样,在录入数据的时候用map存一下每个元素的个数,然后根据数据范围得出幂的范围应该在1~31之间,于是依次枚举2的1次方..2的31次方,然后判断1~n个元素里有没有存在另一个元素使得他两的和等于此时的2的幂(假设为sum好了),这个时候不用挨个去遍历找了,直接用mp[sum-a[i]]来判断其对应元素是否存在就好啦,如果成功的话打个tag,下次遇见这个元素就知道它不用被删除了√。最后的最后是对打tag的地方处理一遍,没有标记的就是要删除的数~

    坑点:如果数组元素中存在本身就是2的几次幂的数,需要判断处理一下当sum-a[i]==a[i]时,如果mp[a[i]]==1则不能打tag,如果>=2的话才可以~

    map<ll,int> mp,mmp,qwq;
    int main(){
        for(int i = 0;i < n;++i){
            cin>>a[i];    qwq[a[i]]++;
        }
        if(n==1)return puts("1"),0;
        sort(a,a+n);
        for(int i = 1;i<= 31;++i){
            sum<<=1;
            if(sum>a[n-1]+a[n-2])break;
            for(int j = 0;j <n;++j){
                if(sum-a[j]<=0)break;
                if(mp[a[j]])continue;
                if(qwq[sum-a[j]]){
                    if((sum == (a[j]+a[j]))&&qwq[a[j]]>=2)mp[a[j]] = 1;
                    else if(sum != a[j]+a[j])mp[a[j]] = mp[sum-a[j]] = 1;
                }
            }
        }
        for(int i = 0;i < n;++i){if(!mp[a[i]])ans++;}
    }    

    D.Polycarp喜欢被3整除的数字,给一个1~2*1e5位数的数字(直接当字符串看啦),在上面进行切割,切割后尽可能让多的区间的每部分的位数相加和为3的倍数,求出最多可以形成多少个这样的区间,不含前导零。

    解法:d挺简单的其实,个人认为还没有c好玩(也可能是c这类遇上的比较少),就每个数对3取余只有0,1,2三个数,其中余数为0的是3的倍数,余数为1与余数为2的相加也是,三个余数为1或者三个余数为2的相加也是。所以就遇见余数为0的ans++,如果遇见1之后遇见了2也ans++然后统计的地方清零,先2后1同理........

            cin>>s;int l = s.size();
        int now = 0;int tp = 0;
        for(int i = 0;i< l;++i){
            if(s[i]=='0'||s[i]=='3'||s[i]=='9'||s[i]=='6'){
                ans++;now = 0;tp = 0;
            }
            else if(s[i]=='2'||s[i]=='5'||s[i]=='8'){
                if(now==0)now =1,tp++;
                else if(now==2)ans++,now = 0,tp = 0;
                else if(now==1){
                    tp++;if(tp==3)ans++,now = 0,tp = 0;
                }
            }
            else if(s[i]=='1'||s[i]=='4'||s[i]=='7'){
                if(now==0)now = 2,tp++;
                else if(now==1)ans++,now = 0,tp = 0;
                else if(now==2){
                    tp++;if(tp==3)ans++,now = 0,tp = 0;
                }
            }
        }
        cout<<ans<<endl;    

    从这题开始以后基本上是自闭补题了,打了一年div3还不能稳定4题,还是练的太少了+不够认真。(碎碎念(蒟蒻反思自己

    (被学弟打爆,然后还老挨骂,暴哭(反向奶——抱着lj这学期肯定进不了实验室qwq也没机会出去打比赛的心态好好学

    E1.给出整数n和m,还有p1~pn的排列,排列中1~n恰好出现一次。定义:中位数是位于非降序排序后序列的中间,如果序列长度为偶数,则使用两个中间元素的左侧。求有多少区间的中位数为m

    解法:根据题目给出的条件可以知道,只有包含m的区间才可能以m为中位数。然后仔细想想,m的位置只和比它大还有比它小的数有关,于是从m的位置往左往右走一遍,遇见比m大的+1,小的则-1,用两个数组维护一下x,统计出每个值出现次数,然后当两个区间的和加起来为0或者为1的时候m为组合区间的中位数

            cin>>n>>m;
        for(int i = 1;i <= n;++i){
            cin>>a[i];if(a[i]==m)tp = i;
        }
        sum[tp] = 0;mmp[0]++;mp[0]++;//这个地方注意x m的单区间左右都放放
        for(int i = tp-1;i >0;--i){
            if(a[i]>m)sum[i] = sum[i+1]+1;
            else if(a[i]<m)sum[i] = sum[i+1]-1;
            else sum[i] = sum[i+1];
            mp[sum[i]]++;
        }
        for(int i = tp+1;i <=n;++i){
            if(a[i]>m)sum[i] = sum[i-1]+1;
            else if(a[i]<m)sum[i] = sum[i-1]-1;
            else sum[i] = sum[i-1];
            mmp[sum[i]]++;
        }
        int cnt;ll ans = 0;
        if(mp.size() < mmp.size()){//感觉这里不用大小比较优化似乎也行?
            for(iter1 = mp.begin();iter1!=mp.end();iter1++){
                cnt = iter1->first;cnt*=(-1);
                ans+=( mmp[cnt] * iter1->second);
                ans+=(mmp[cnt+1] * iter1->second);
            }
        }
        else {
            for(iter1 = mmp.begin();iter1!=mmp.end();iter1++){
                cnt = iter1->first;cnt*=(-1);
                ans+=( mp[cnt] * iter1->second);
                ans+=(mp[cnt+1] * iter1->second);
            }
        }
        cout<<ans<<endl;

    E2.定义和E1差不多 就是给出的排列不一定是1~n只出现一次。

    解法:在别人的博客上学的,求中位数刚好为m的情况在此时可能有点复杂,但是可以通过求中位数大于等于m的区间数减去中位数大于等于m+1的区间数得到答案。

    那么该怎么求中位数大于等于m的区间数,根据定义知道,当该区间>=m的数大于<m的数,那么此时区间的中位数大于等于m。

    //终于理解清思路了

    也是用+-1来维护区间内大于m和小于m的数的多少,要求[a,b]这个区间是大于0还是小于0可以用[1,b]-[1,a-1]得到。(前缀和思想)

    为了防止下标为负数的数组越界问题,我们开两倍数组ape[2*N]用来存储某个值出现的次数,cnt初始化为n,用于维护1~i的前缀和。sum用来维护在[1,i-1]处有多少个值小于当前cnt(这样就可以知道以i为右端点的区间,有多少个是大于0的了)。然后枚举右端点,当我们加入一个大于等于m的端点时,就有sum+ape[cnt]个端点可以和该端点匹配,cnt++;小于m时,cnt--,sum-=ape[cnt]。最后累加得解

    //好艰难地理清了表述,可能后期有了更好的理解会更新表述吧。

    int a[N],ape[2*N],n;
    ll sv(int m){
        mem(ape, 0);
        int cnt = n;ape[cnt]++;
        ll sum = 0,ans = 0;
        for(int i = 0;i < n;++i){
            if(a[i] >= m){
                sum+=ape[cnt];cnt++;
            }
            else {
                cnt--;sum-= ape[cnt];
            }
                    ape[cnt]++;ans+=sum;
        }
        return ans;
    }
    int main(){
        int m;ll ans;
        cin>>n>>m;
        for(int i = 0;i < n;++i)cin>>a[i];
        ans = sv(m)-sv(m+1);
        cout<<ans<<endl;
    }    

    https://codeforces.com/contest/1005/problem/F

    参考博客   https://www.cnblogs.com/widsom/p/9290144.html

    F.最短路树,给n个点和m条边,首都编号为1,设di为首都到第i个城市要走的路,最小化(d2+...+dn),有多个方案则输出多个方案,以01串的方式(选取该条边则1),若方案大于k则输出k个。

    解法:bfs是用dijkstra是思想构建图,然后回到main建树,dfs查询方案输出结果

     1 int n,m,k,dis[N],u,v;
     2 char s[N];bool vis[N];
     3 vector<pii>g[N];
     4 vector<int>pre[N];
     5 vector<string>res;
     6 void bfs(){
     7     pii tp;queue< pii > q;int v;
     8     dis[1] = 0;vis[1] = true;
     9     q.push({1,0});
    10     while(!q.empty()){
    11         tp = q.front();q.pop();
    12         for(int i = 0;i < g[tp.fi].size();++i){
    13              v = g[tp.fi][i].fi;
    14              if(!vis[v]){
    15                  vis[v] = true;
    16                 dis[v] = tp.se + 1;
    17                 q.push({v,dis[v]});
    18              }
    19         }
    20     }    
    21 }
    22 void dfs(int u){
    23     if(res.size() >= k)return ;
    24     if(u > n){
    25         res.pb(s+1);return;
    26     }
    27     for(int i = 0;i < pre[u].size();++i){
    28         s[pre[u][i]] = '1';
    29         dfs(u+1);
    30         s[pre[u][i]] = '0';
    31     }
    32 }
    33 int main(){
    34     fio
    35     cin>>n>>m>>k;
    36     for(int i = 1;i <= m;++i){
    37         cin>>u>>v;
    38         g[u].pb({v,i}),g[v].pb({u,i});
    39     }
    40     bfs();
    41     pii p;
    42     for(int i = 2; i <= n;++i){
    43         for(int j = 0;j < g[i].size();++j){
    44             p = g[i][j];
    45             if(dis[p.fi]+1 == dis[i]) pre[i].pb(p.se);    
    46         }
    47     }
    48     for(int i = 1;i <= m;++i)s[i] = '0';
    49     dfs(2);
    50     cout<<res.size()<<endl;
    51     for (int i = 0; i < res.size(); i++) cout << res[i] << endl;
    52     return 0;
    53 } 
  • 相关阅读:
    VMware安装CentOS系统与配置全过程
    Matplotlib学习笔记
    python正则表达式字符记录
    HyperLedger Fabric 学习思路分享
    fabric-sdk-container v1.0-beta 新增支持多服务节点
    HyperLedger/Fabric SDK使用Docker容器镜像快速部署上线
    HyperLedger/Fabric JAVA-SDK with 1.1
    HyperLedger Fabric 1.1 手动部署单机单节点
    Hyperledger Fabric CA User’s Guide——配置设置(四)
    Hyperledger Fabric CA User’s Guide——开始(三)
  • 原文地址:https://www.cnblogs.com/h404nofound/p/12208740.html
Copyright © 2011-2022 走看看