King of Range
链接
题目大意:给定的一个区间内,最小值与最大值,要严格大于题目给出的k,问这样的区间有几个
思路:比赛的时候,一开始暴力,但会tle,后面用指针,然后用map存储最大最小,但是仍旧超时,方法是可以用模拟队列,一个维护最大一个最小,类似滑动窗口,可以输出结果。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,k;
ll a[100005];
ll v[100005],qmax[100005],qmin[100005]; //一个维护最大,一个维护最小
void solve(){
scanf("%lld %lld",&n,&m);
for (int i = 1; i <= n; ++i)
scanf("%lld",&a[i]);
while(m--){
ll ans=0,tmp=1;
ll head1=1,tail1=0;
ll head2=1,tail2=0;
scanf("%lld",&k);
for(int i=1;i<=n;i++){
while(head1<=tail1&&a[i]>=a[qmax[tail1]]) tail1--; //对入队出队用tail来操作
qmax[++tail1]=i;
while(head2<=tail2&&a[i]<=a[qmin[tail2]]) tail2--;
qmin[++tail2]=i;
while(head1<=tail1&&head2<=tail2&&a[qmax[head1]]-a[qmin[head2]]>k){
ans+=n-i+1;
tmp++;
if(qmax[head1]<tmp) head1++;
if(qmin[head2]<tmp) head2++;
}
}
printf("%lld\n",ans);
}
}
int main(){
solve();
}
Querying Multiset
链接
这道题还是一道简单的题,不过stl用的不熟练,没有写完,思路也很简单,就是一道模拟题,输入1,2,3,分别对应了三种操作,按照要求操作就可以。
思路用小根堆存储,每次出队头即可
#include<bits/stdc++.h>
using namespace std;
typedef long long int LLD;
int main()
{
int q;
LLD sum = 0;
priority_queue<LLD, vector<LLD>, greater<LLD> >pq; //优先队列,小根堆
scanf("%d", &q);
for (int i = 0; i<q; i++)
{
LLD tmp_q, x;
scanf("%lld", &tmp_q);
if (tmp_q == 1)
{
scanf("%lld", &x);
pq.push(x - sum);
} else if (tmp_q == 2) {
scanf("%lld", &x);
sum += x;
} else {
x = pq.top();
printf("%lld\n", (x + sum));
pq.pop();
}
}
return 0;
}
Boxes
链接
震惊三观。。。。。。。题目说有n个盒子,每个盒子里面有一个黑球或者白球,我们要知道每个盒子里是什么球,需要最少的花费是多少,其中一种操作是直接花费wi开一个盒,另一种操作是花费c,来得知剩下的盒子里有多少黑球。
思路:迭代的思想,先对w数组排序,每次开盒开最小的一个,之后的开盒代价为代价为c+sumwi(1-1/(2^(n-1))
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
//int w[N];
double w[N];
int main()
{
// ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n;
double c;
cin >> n >> c;
double sum = 0, ans = 0;
for (int i = 1; i <= n; i ++ ) scanf("%lf", &w[i]), sum += w[i];
sort(w + 1, w + n + 1);
for (int i = 1; i <= n; i ++ ) ans = ans / 2 + w[i];
printf("%.8lf\n", min(sum, sum - ans + c));
return 0;
}
Math
链接
题目大意就是要我们给出一个对,使得xy+1|x^2 +y^2成立,就是前面那个可以整除后面那个式子
就是一道打表的问题,但是要考虑时间超时的问题,要找到i^3<=n来优化。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
ll a[10000005];
int main() {
int T;
long long n;
long long N = 1e18;
cin >> T;
int ln = 0;
for (long long i = 2; 1ll * i * i * i <= N; i++) {
long long x = i, y = i * i * i;
while (y <= N) {
a[++ln] = y;
if ((N + x) / i / i < y) break; //不满足条件,break
long long tmp = y * i * i - x;
x = y;
y = tmp;
}
} //通过规律不断更新(x,y),并记录下y值
sort(a + 1, a + ln + 1); //由于存入的y每个k不同,需排序
while (T--) {
cin >> n;
int x = upper_bound(a + 1, a + ln + 1, n) - a; //二分查找,返回个数
cout<<x<<endl;
}
}
Scholomance Academy
链接
这道题题意真的非常难以理解,它的大意是有一个值thita,把它当做0,比它大的都为正,比它小的都为负,题目每次会给你两个量,一个量是+,-表示猜测值,和一个具体数值,要你根据thita来判断它是正是负,以此来得出4个量,再又4个量,来计算出一个值,然后在图中得出一个点,根据thita的变动,我们可以得出一个图,再得出这个曲线的积分也就是面积。
数据量是1e6,我们想的就是,模拟这些数,来得出这个图的转折点在哪,因为这个图一定是一些横着的线组成的。
#include<bits/stdc++.h>
using namespace std;
vector<int>a,b;
int main()
{
int n;
cin >> n;
for(int i=1;i<=n;i++)
{
char c;
int x;
cin >> c >> x;
if(c=='+')
a.push_back(x);
else
b.push_back(x);
}
sort(a.begin(),a.end());
sort(b.begin(),b.end());
double ans=0;
for(auto i:b)
ans=ans+a.end()-upper_bound(a.begin(),a.end(),i);
printf("%.10lf\n",ans/(a.size()*b.size()));
return 0;
}