H Holding Two
题意:
给出n,m,要求用1和0构造一个 n*m 的矩阵,使得其中不存在三个相同的数在一条线上(包括横线、竖线、斜线),若能构造,输出这个矩阵,不能输出-1。
思路:
构造得到了一个满足条件的矩阵
0011001100……
1100110011……
0011001100……
1100110011……
………………
其长和宽均可无限循环延长,故对于任意的m和n,输出该矩阵的一部分即可。
代码:
#include<iostream>
using namespace std;
int a[1020][1020];
int main(){
int n,m;
cin>>n>>m;
/*if(n<3||m<3){
printf("")
}*/
a[0][0]=0;a[0][1]=0;a[0][2]=1;a[0][3]=1;
for(int i=4;i<1005;i++){
a[0][i]=a[0][i-4];
}
for(int i=1;i<1005;i++){
for(int j=0;j<1005;j++){
a[i][j]=1-a[i-1][j];
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cout<<a[i][j];
}
cout<<endl;
}
}
B Boxes
题意:
一共有n个盒子,每个盒子里面装黑球和白球的概率各为1/2,各个盒子间相互独立,打开一个盒子需要支付Wi的代价。你还可以选择支付C,来知道总共有多少个黑球。求弄清每一个盒子里球的颜色需要支付的最小代价的期望。
思路:
分为两种情况。第一种不支付C,打开所有盒子,总代价为;
第二种先支付C,此时我们已知了有k个黑球,将w排序后依次打开盒子,直到剩下的盒子里都是黑球或者白球时,停止。从反方向考虑,也就是一组随意数后 i 个都是同一颜色的概率 * 打开前 n-i 个盒子需要的总代价, 最后对i累和即可。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n;
double a[N], sum[N];
double res, c;
int main(){
cin>>n>>c;
for(int i=1; i<=n; ++i){
scanf("%lf", &a[i]);
}
sort(a+1,a+n+1);
for(int i=1; i<=n; ++i){
sum[i]=sum[i-1]+a[i];
}
res=c;
double p=1;
for(int i=1; i<n; ++i){
p/=2.0;
res+=sum[n-i]*p;
//res+=sum[n-i]*(1.0/(1<<i));
}
double ans=min(res,1.0*sum[n]);
printf("%.10lf", ans);
}
K King of Range
题意:
给定 n 个整数 a[n] 和 m次查询。对于每个查询,都会给您一个常量k,求有多少不同的(l,r) 满足子序列 a[l] ~ a[r] 的中最大值减去最小值大于k。
思路:
尺取。对于满足条件的(l ,r),易知右端点取在 r 后的值也能满足,r 搜索到这一点后停止,ans+=n-r+1。l 在往后移动一位的时候,满足条件的结尾一定在r 点或之后,所以r 的起点还是当前位置,然后继续按照第一步继续,直到统计完成。
需要记录每一次改变l 和r 后区间的最小值和最大值,可以用双端队列实现。
代码:
#include <cstdio>
#include <iostream>
#include <deque>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxN = 1e5 + 7;
typedef long long ll;
int m, n, a[maxN];
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
for(int i = 1; i <= m; ++i) {
int k;
scanf("%d", &k);
deque<int> maxPos, minPos; //双端队列维护当前最大值和最小值 (maxPos.front() )
int l = 1,r = 0; //所取区间的起点l,终点r
ll ans = 0;
while(l <= n && r <= n) {
while((!maxPos.empty()) && maxPos.front() < l)
maxPos.pop_front();//前一个数在起点之前,删去
while((!minPos.empty()) && minPos.front() < l)
minPos.pop_front();
if((!maxPos.empty()) && a[maxPos.front()] - a[minPos.front()] > k) {
ans += n - r + 1; //选取之后的点作为结尾,也满足条件
++l;
continue;
} else {
++r;
while(!maxPos.empty() && a[maxPos.back()] <= a[r])
maxPos.pop_back();
maxPos.push_back(r);//更改最大值
while(!minPos.empty() && a[minPos.back()] >= a[r])
minPos.pop_back();
minPos.push_back(r);//更改最小值
}
}
printf("%lld\n", ans);
}
return 0;
}
总结:
这场比赛过了一题。
H题是构造,几次尝试之后成功AC。然后开了B题和K题。K题想到了是尺取,但是不知道怎样记录每次变化后的最小值和最大值,时间复杂度降不下来。题解用的双端队列,很妙0v0。以后对STL的运用上要加强。B题没有想到反面思考,用的是递归还有二项分布,TLE了三次……
这场下来总体的感觉是数学没学好,想的太复杂了,两题都是TLE。以后要好好学习,重新做人。