Codeforces Round #689 (Div. 2, based on Zed Code Competition)
地址:https://codeforces.ml/contest/1461
A:
题意是用abc构造一个以最多以k为循环的回文子串,总长度为n
思路: 只需要顺序在一个循环节内输出同一种字符,下一个循环节输出下一种字符就好了
代码:
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<map>
#include<iostream>
using namespace std;
typedef long long ll;
const int N = 10010;
int main() {
int t;
cin>>t;
while(t--) {
int n,k;
cin>>n>>k;
int f = 0;
for(int i=1; i<=n; i++) {
if(i%k !=0) {
printf("%c",'a'+(f%3));
} else {
f++;
printf("%c",'a'+(f%3));
}
}
puts("");
}
return 0;
}
B:
思路: 由下往上递推,一个位置所包含的点数必然是由它下面的三个点所递推过来的,只需要在这三个点中选取最小的就好了
代码:
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<map>
#include<iostream>
using namespace std;
typedef long long ll;
const int N = 1010;
char a[N][N];
int f[N][N];
int n,m;
int judge(int x,int y) {
if(a[x][y]!='*') return 0;
if(a[x][y] =='*')
if(x==n|| y==1|| y==m) return 1;
int minn = 0x3f3f3f3f;
for(int i=y-1;i<=y+1;i++) {
minn=min(minn,f[x+1][i]+1);
}
return minn;
}
int main() {
int t;
cin>>t;
while(t--) {
memset(f,0,sizeof f);
cin>>n>>m;
int sum = 0;
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
cin>>a[i][j];
}
}
int res = 0;
for(int i=n; i>=1; i--) {
for(int j=1; j<=m; j++) {
res += judge(i,j);
f[i][j] = judge(i,j);
}
}
cout<<res<<endl;
}
return 0;
}
C:
思考 一组数组完全排序好后的概率是受最后变化的那个数的影响,
举个例子 n = 4 [3,1,2,4] 排序好后是[1,2,3,4] 其中最后变化的数字是i = 3 ,当任意的r<i 的位置,对于整个序列的升序是没有贡献的,所以只需要考虑最后一个变化的数就行了
同时,我们直接算成为升序的概率p不好算,可以考虑1-p的这一面。
先算出一系列操作后仍不为升序的概率,最后用1减去即可
代码:
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<map>
#include<iostream>
using namespace std;
typedef long long ll;
const int N = 100010;
int n,m;
int a[N],b[N];
int main() {
int t;
cin>>t;
while(t--) {
cin>>n>>m;
for(int i=1; i<=n; i++) {
cin>>a[i];
b[i] = a[i];
}
sort(b+1,b+1+n);
int p = n;
while(p>0 && a[p]==b[p])
p--;
double res = 1.0;
while(m--) {
int r;
double ex;
cin>>r>>ex;
if(r>=p){
res *= (1-ex);
}
}
if(p) printf("%.6lf\n",1-res);
else
printf("%.6lf\n",1.0);
}
return 0;
}
D:
题意是给定一数组,递归每次以最大数和最小数之和/2 为划分界限,
m次询问,每次给你一个s,问是否有一个[l,r]的区间和等于s
预处理记录一下各自区间的和, [l,r]区间的和可以用前缀和 s[r]-s[l-1] 来表示(s 为前缀和数组)
在递归的时候,每次二分寻找大于l+r>>1 的位置作为mid的位置
代码:
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<map>
#include<iostream>
using namespace std;
typedef long long ll;
const int N = 100010;
int n,q;
ll a[N];
ll s[N];
map<ll,ll> mp;
void f(int l,int r) {
int mid = upper_bound(a+1,a+1+n,a[l]+a[r]>>1)-a;
if(a[l]!=a[r]) {
f(l,mid-1);
f(mid,r);
}
mp[s[r]-s[l-1]] = 1;
}
int main() {
int t;
cin>>t;
while(t--) {
mp.clear();
cin>>n>>q;
for(int i=1; i<=n; i++)
cin>>a[i];
sort(a+1,a+1+n);
for(int i=1; i<=n; i++)
s[i] = s[i-1] + a[i];
f(1,n);
while(q--) {
ll x;
cin>>x;
if(mp[x])
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
}