把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

20180712练习赛 [CF]EDU ROUND1-2

A - Extract Numbers CodeForces - 600A
B - Queries about less or equal elements CodeForces - 600B
C - Tricky Sum CodeForces - 598A
D - Queries on a String CodeForces - 598B
E - Igor In the Museum CodeForces - 598D
F - Make Palindrome CodeForces - 600C


A【实现细节】

题目简述:
许多个字符串由‘,’或‘;’ 隔开 (可能为空) 第一行输出所有数字(不含前导0和小数),第二行输出所有单词
用逗号隔开 空的字符串视为单词 如果没有数字或单词 输出‘-’

思路分析:
这道题要特别注意细节 考场上没有把每个字符串取出来 用指针标记 查错特别不好查!!!尤其是空字符串
其实有明显区分的话可以把每个字符串取出来 再依次判断、存储 代码比较清晰
最好用STL比较简单 vector轻松搞定
判断等功能性比较强的代码可以写成函数
另外string有几个函数

s.clear();(清除函数)
s.push_back(a);(在字符串后面插入一个字符)
#include<cstdio>
#include<iostream>
#include<vector>
#include<string>
#include<cstring>
#define MAXN 100005
using namespace std;
vector<string> A,B;
char str[MAXN];
bool check(string x)
{
    if(x.size()==0) return 0;
    if(x[0]=='0'&&x.size()>=2) return 0;
    for(int i=0;i<x.size();i++)
        if(x[i]<'0'||x[i]>'9') return 0;
    return 1;
}
void print()
{
    if(A.size()==0)
        printf("-\n");
    else{
        printf("\"");
        for(int i=0;i<A.size();i++)
        {
            if(i==0) cout<<A[i];
                else cout<<","<<A[i];
        }
        printf("\"\n");
    }

    if(B.size()==0)
        printf("-");
    else{
        printf("\"");
        for(int i=0;i<B.size();i++)
        {
            if(i==0) cout<<B[i];
                else cout<<","<<B[i];
        }
        printf("\"");
    }
}
int main()
{
    fgets(str,MAXN,stdin);
    int len=strlen(str);
    string x;
    x.clear();
    for(int i=0;i<len;i++)
    {
        if(str[i]==','||str[i]==';'||str[i]=='\n')
        {
            if(check(x)) A.push_back(x);
                else B.push_back(x);
            x.clear();
        }
        else x.push_back(str[i]);
    }
    print();
}

B

不解释

#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 200005
int N,M;
int a[MAXN],b[MAXN];
int main()
{
    scanf("%d %d",&N,&M);
    for(int i=1;i<=N;i++)
        scanf("%d",&a[i]);
    for(int j=1;j<=M;j++)
        scanf("%d",&b[j]);
    sort(a+1,a+N+1);
    for(int j=1;j<=M;j++)
    {   
        int t=upper_bound(a+1,a+N+1,b[j])-a;
        printf("%d",t-1);
        if(j<M) printf(" ");
    }

C

思路分析:
预处理一个常数数组
可以先用求和公式算总和然后再减2倍
会爆int

之前用了个upper_bound() 然后错了 (样例都过不了)
后来觉得lower_bound() 才对 然后第二个点就WA了
然后在不会T的时候还是不用吧
至今未果 寻病终(画风似乎不对)
https://blog.csdn.net/cqbzlytina/article/details/81122583

好的 似乎找到了 没有特判 p[t]!=N 的情况
而且常数数组有30个 下标从0~29
要多找几种情况自己验证一下

#include<cstdio>
#include<algorithm>
using namespace std;
long long p[]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912};
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        long long N;
        scanf("%lld",&N);
        long long ans=(1+N)*N/2;
        //int t=upper_bound(p,p+29,N)-p-1;
        for(int i=0;i<=29;i++)
        {
            if(N>=p[i])
                ans-=2* p[i];
            else break;
        }
        printf("%lld\n",ans);
    }
}
//lower_bound()
#include<cstdio>
#include<algorithm>
using namespace std;
long long p[30]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912};
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        long long N;
        scanf("%lld",&N);
        long long ans=(1+N)*N/2;
        int t=lower_bound(p,p+30,N)-p;
        if(p[t]!=N) t--;
        for(int i=0;i<=t;i++)
            ans-=2* p[i];
        printf("%lld\n",ans);
    }
}

D

题意简述:
一个字符串 给出如下操作:
l r k
表示区间[l,r]的字符段轮换k次(最右边的移到最左边,然后依次轮换)
思路分析:
模拟题
由于轮换 没有必要模拟k次 注意取余的小技巧

#include<cstdio>
#include<cstring>
using namespace std;
#define MAXN 10005
char s[MAXN],t[MAXN];
int main()
{
    scanf("%s",s+1);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int l,r,x;
        scanf("%d %d %d",&l,&r,&x);
        int len=r-l+1;
        x%=len;
        memcpy(t,s,sizeof(s));
        for(int j=l;j<=r;j++)
            t[(j-l+x)%len+l]=s[j];
        memcpy(s,t,sizeof(t));
    }
    puts(s+1);
}

E

题意简述:
给出n×m的博物馆的图和Igor的位置 ‘.’可以走而 ‘*’是墙,不可以走
和Igor相邻的‘*’上的画可以被Igor看见,问Igor最多能看见多少幅画
(Igor的位置有k组数据)
思路分析
暴搜 只要撞到了墙就ans++ 注意判重 然而会T
然后可以“记忆化”一下 每到一个位置 就记录一下这个位置能看到的画的数量 然后下次可以直接用

//dfs 每次都重新搜 TLE
#include<cstdio>
#define MAXN 1005
int N,M,ans;
const int dx[]={0,0,1,-1},dy[]={1,-1,0,0};
char mapp[MAXN][MAXN];
bool vis[MAXN][MAXN];
bool check(int x,int y)
{
    if(x<1||x>N||y<1||y>M) return 0;
    return 1;
}
void dfs(int x,int y)
{
    if(mapp[x][y]=='*') 
    {
        ans++;
        return ;
    }
    vis[x][y]=1;
    for(int i=0;i<4;i++)
    {
        if(!check(x+dx[i],y+dy[i])||vis[x+dx[i]][y+dy[i]]) continue;
        dfs(x+dx[i],y+dy[i]);
    }
    return ;
}
int main()
{
    int T;
    scanf("%d %d %d",&N,&M,&T);
    for(int i=1;i<=N;i++)
        scanf("%s",mapp[i]+1);
    while(T--)
    {
        int x,y;
        ans=0;
        scanf("%d %d",&x,&y);
        dfs(x,y);
        printf("%d\n",ans);
    }
}
//每次搜索时 记录下当前点能看到的画的数量 下次若查询到 直接用
#include<cstdio>
#define MAXN 1005
#define MAXP 100005
int N,M,ans[MAXP],cnt/*编号*/;
const int dx[]={0,0,1,-1},dy[]={1,-1,0,0};
char mapp[MAXN][MAXN];
int vis[MAXN][MAXN];
bool check(int x,int y)
{
    if(x<1||x>N||y<1||y>M) return 0;
    return 1;
}
void dfs(int x,int y)
{
    vis[x][y]=cnt;
    for(int i=0;i<4;i++)
    {
        int xn=x+dx[i],yn=y+dy[i];
        if(vis[xn][yn]) continue;
        if(mapp[xn][yn]=='*') ans[cnt]++;
        else dfs(xn,yn);
    }
}
int main()
{
    int T;
    scanf("%d %d %d",&N,&M,&T);
    for(int i=1;i<=N;i++)
        scanf("%s",mapp[i]+1);
    while(T--)
    {
        int x,y;
        scanf("%d %d",&x,&y);
        if(vis[x][y])
        {
            printf("%d\n",ans[vis[x][y]]);
            continue;
        }
        cnt++;
        dfs(x,y);
        printf("%d\n",ans[vis[x][y]]);
    }
    return 0;
}

然后编号不一定非要用一个二维数组来存
每一个坐标(x,y)都可以唯一对应一个整数
当然这道题本来就要用一个vis数组标记是否访问
在dfs具有一些特性时,可以在vis上动手脚


F

题意简述:
给出一个字符串,可以改变其中的字符,将它用少的操作步数将它变成回文串。顺序也可以任意改变,但不会算操作步数。输出字典序最小的那个回文串
思路分析:
贪心的思想 记录每种字符的数量 如果某种字符的数量是偶数 那么可以前一个、后一个行程回文 如果数量为奇数 那么肯定会单一个
把单的统计出来 字典序最小 那么就让最大的和最小的配对,然后把最大的变成最小的,以此类推······
(其实事实上是后面的字符与前面k小的配成k对就能满足 这么写是等效的 而且方便些)

#include<cstdio>
#include<cstring>
using namespace std;
#define MAXN 200005
char s[MAXN],trans[30];
int num[30];
int main()
{
    int t=0;
    char mid='0';
    scanf("%s",s);
    int len=strlen(s);
    for(int i=0;i<len;i++)
        num[s[i]-'a']++;
    for(int i=0;i<26;i++)
        if(num[i]%2) trans[++t]=i+'a';
    for(int i=1;i<=t/2;i++)
    {
        num[trans[i]-'a']++;
        num[trans[t-i+1]-'a']--;
    }
    if(len%2) mid=trans[t/2+1];

    int F=0,B=len-1;
    for(int i=0;i<26;i++)
    {
        for(int j=F;j<F+num[i]/2;j++)
            s[j]=i+'a';
        F+=num[i]/2;
        for(int j=B;j>B-num[i]/2;j--)
            s[j]=i+'a';
        B-=num[i]/2;
    }
    if(len%2) s[len/2]=mid;
        puts(s);
    return 0;
}
posted @ 2018-07-23 21:48  Starlight_Glimmer  阅读(10)  评论(0编辑  收藏  举报  来源
浏览器标题切换
浏览器标题切换end