题意 : 给定每个物品使得成功一次的概率,求选一些物品使得成功一次的概率最大
分析: 从大到小排序,依次加入每个物品。
const int maxn = 1e5 + 10;
double p[maxn];
int main(void)
{
int T;
cin >> T;
while (T--) {
int n; cin >> n;
for (int i = 1; i <= n; ++i) {
scanf("%lf", &p[i]);
}
sort(p + 1, p + n + 1);
if (p[n] >= 0.5) {
printf("%.10f\n", p[n]);
}
else {
long double t0 = 1, t1 = 0;
for (int i = n; i >= 1; --i) {
long double t00 = t0 * (1 - p[i]);
long double t11 = t1 * (1 - p[i]) + t0 * p[i];
if (t11 < t1) break;
t0 = t00;
t1 = t11;
}
double ans2 = t1;
printf("%.10f\n", ans2);
}
}
return 0;
}
队友写的
set 维护即可
typedef pair<LL,LL> P;
const int maxn = 1e5+10;
P p[maxn];
int main(void)
{
int T;cin>>T;
while(T--){
int n;cin>>n;
for(int i = 1;i <=n; ++i){
scanf("%lld%lld",&p[i].first,&p[i].second);
}
sort(p+1,p+n+1);
LL M = -2e18;
set<P> s;
for(int i = n;i >= 1; --i){
s.insert(P(p[i].second,i));
}
LL minabs = 2e18;
for(int i = n;i >= 1; --i){
s.erase(P(p[i].second,i));
minabs = min(minabs,abs(M-p[i].first));
auto it = s.lower_bound(P(p[i].first,i));
if(it != s.end()&&(*it).first > M)
minabs = min(minabs,abs((*it).first-p[i].first));
if(it != s.begin()){
--it;
if((*it).first > M) minabs = min(minabs,abs((*it).first-p[i].first));
}
M = max(M,p[i].second);
}
cout<<minabs<<endl;
}
return 0;
}
题意: 给定n组物品,每组物品分别有两个, a i , b i a_i,b_i ai,bi,求取 1 , 2 , … , 2 ∗ n 1,2,\dots,2*n 1,2,…,2∗n个物品的最大价值,限制条件,如果想取 b i b_i bi 必须先取 a i a_i ai.
分析:
每次选有两种选择:
对于第一种情况,我们只需要维护一个物品的优先队列,如果 a i a_i ai选了,就把 b i b_i bi加进去
对于第二种情况, 回退,将上次选的一个放回到优先队列中去,我们还需要维护一个 a i , b i a_i,b_i ai,bi对的最大值的优先队列
#include
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define me(ar) memset(ar,0,sizeof(ar))
#define lowbit(x) (x&(-x))
#define Pb push_back
#define FI first
#define SE second
#define rep(i,a,n) for (int i=a;i
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define IOS ios::sync_with_stdio(false)
#define DEBUG cout<
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int prime = 999983;
const int INF = 0x7FFFFFFF;
const LL INFF =0x7FFFFFFFFFFFFFFF;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-6;
const LL mod = 1e9 + 7;
LL qpow(LL a,LL b){LL s=1;while(b>0){if(b&1)s=s*a%mod;a=a*a%mod;b>>=1;}return s;}
LL gcd(LL a,LL b) {return b?gcd(b,a%b):a;}
int dr[2][4] = {1,-1,0,0,0,0,-1,1};
typedef pair<int,int> P;
const int maxn = 1e5+10;
struct Val {// 维护一个物品的
int first, second;
int belong;
} ;
struct Str {// 维护一对物品的
int first, second;
int th;
};
bool operator < (const Str &a, const Str &b) {
return a.first < b.first;
}
bool operator < (const Val &a, const Val &b) {
return a.first + a.second < b.first + b.second||(a.first + a.second == b.first + b.second&& a.first > b.first);
}
Val val[maxn];
int f[maxn];
int t[maxn];// t[0] 代表两个都没选,t[1] 代表只选了a_i,t[2] 代表选了a_i,b_i
int who[maxn], pre[maxn];// 如果本次只选了一个,那么我们需要知道是哪一对,并且知道它的值
int main(void)
{
int T; cin >> T;
while (T--) {
int n; scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d%d", &val[i].first, &val[i].second);
val[i].belong = i;
}
for (int i = 1; i <= 2 * n; ++i)
t[i] = f[i] = who[i] = pre[i] = 0;
priority_queue<Str> Q1;
priority_queue<Val> Q2;
for (int i = 1; i <= n; ++i) {
Q1.push(Str{val[i].first, i, 0});
Q2.push(val[i]);
}
for (int i = 1; i <= 2 * n ; ++i) {
while (!Q1.empty()) {
if (Q1.top().th != t[Q1.top().second]) Q1.pop();
else
break;
}
while (!Q2.empty()) {
if (t[Q2.top().belong] != 0) Q2.pop();
else break;
}
// 先把不合法的状态都退掉
int a = f[i - 1] + Q1.top().first;// a 代表本次选一个
int b = 0;// b 代表选两个
if (!Q2.empty() && pre[i - 1]) {
b = f[i - 1] - pre[i - 1] + Q2.top().first + Q2.top().second;
}
if (a >= b) {
f[i] = a;
pre[i] = Q1.top().first; who[i] = Q1.top().second;
Q1.pop();
if (t[who[i]] == 0) {
t[who[i]] = 1;
Q1.push(Str{val[who[i]].second, who[i], t[who[i]]});
}
else
t[who[i]] = 2;
}
else {
f[i] = b;
who[i] = Q2.top().belong;
pre[i] = 0;
t[who[i - 1]]--;
Q1.push(Str{pre[i - 1], who[i - 1], t[who[i - 1]]});
t[who[i]] = 2;
Q2.pop();
}
}
for (int i = 1; i <= 2 * n ; ++i) {
printf("%d%c", f[i], " \n"[i == 2 * n]);
}
}
return 0;
}
/*
1
5
1 6
3 4
4 8
10 3
7 7
*/
/*
1
5
1 6
3 4
4 8
10 3
7 7
*/
题意:统计满足 max ( a l , a l + 1 , … , a r ) − ( r − l + 1 ) ≤ k \max({a_l, a_{l+1}, \ldots, a_r}) - (r - l + 1) \leq k max(al,al+1,…,ar)−(r−l+1)≤k的区间个数
分析:第一开始没看到区间中的元素不能重复,写了一发单调栈,发现不太对,然后考虑启发式分治 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))
const int maxn = 3e5 + 10;
int a[maxn], pre[maxn], nxt[maxn], loc[maxn];
int n, k;
int f[maxn][19];
void ST_prework() {
for (int i = 1; i <= n; ++i) f[i][0] = i;
int t = log(n) / log(2) + 1;
for (int j = 1; j < t; ++j) {
for (int i = 1; i <= n - (1 << j) + 1; ++i)
if (a[f[i][j - 1]] > a[f[i + (1 << (j - 1))][j - 1]])
f[i][j] = f[i][j - 1];
else
f[i][j] = f[i + (1 << (j - 1))][j - 1];
}
}
int ST_query(int l, int r) {
int k = log(r - l + 1) / log(2);
if (a[f[l][k]] > a[f[r - (1 << k) + 1][k]])
return f[l][k];
else
return f[r - (1 << k) + 1][k];
}
int tree[maxn];
// void query(int )
LL solve(int l, int r) {
if (r < l) return 0;
int t = ST_query(l, r);
LL ans = 0;
if (t - l < r - t) {
int tmp = min(nxt[t], r + 1);
// cout << t << " " << a[t] << " " << nxt[t] << endl;
for (int i = t; i >= l; --i) {
tmp = min(nxt[i], tmp);
if (tmp <= t) break;
ans += max(0, tmp - max(t, i - 1 + a[t] - k));
}
}
else {
// cout
int tmp = max(pre[t], l - 1);
// cout << tmp << endl;
for (int i = t; i <= r; ++i) {
tmp = max(pre[i], tmp);
if (tmp >= t) break;
// cout << r + 1 - a[t] + k << endl;
ans += max(0, min(t, i + 1 - a[t] + k) - tmp);
// cout << ans << endl;
}
}
// cout << l << " " << r << " " << ans << endl;
ans += solve(l, t - 1);
ans += solve(t + 1, r);
return ans;
}
int main(void)
{
int T; cin >> T;
while (T--) {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
ST_prework();
for (int i = 1; i <= n; ++i)
loc[i] = -1;
for (int i = 1; i <= n; ++i) {
pre[i] = loc[a[i]];
loc[a[i]] = i;
pre[i] = max(pre[i], pre[i - 1]);
}
for (int i = 1; i <= n; ++i)
loc[i] = n + 1;
nxt[n + 1] = n + 1;
for (int i = n; i >= 1; --i) {
nxt[i] = loc[a[i]];
loc[a[i]] = i;
nxt[i] = min(nxt[i], nxt[i + 1]);
}
printf("%lld\n", solve(1, n));
// printf("%lld\n", ans);
}
return 0;
}