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;
}