2019 Multi-University Training Contest 10

2019 Multi-University Training Contest 10

1003

题意 : 给定每个物品使得成功一次的概率,求选一些物品使得成功一次的概率最大
分析: 从大到小排序,依次加入每个物品。

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

1005 Welcome Party

队友写的
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;
}

1008

题意: 给定n组物品,每组物品分别有两个, a i , b i a_i,b_i ai,bi,求取 1 , 2 , … , 2 ∗ n 1,2,\dots,2*n 1,2,,2n个物品的最大价值,限制条件,如果想取 b i b_i bi 必须先取 a i a_i ai.
分析:
每次选有两种选择:

  1. 选一个当前剩下没选的最大值
  2. 如果上次选的是一个,选一对,把上次选的退掉

对于第一种情况,我们只需要维护一个物品的优先队列,如果 a i a_i ai选了,就把 b i b_i bi加进去
对于第二种情况, 回退,将上次选的一个放回到优先队列中去,我们还需要维护一个 a i , b i a_i,b_i ai,bi对的最大值的优先队列



#include <bits/stdc++.h>
#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<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define IOS ios::sync_with_stdio(false)
#define DEBUG cout<<endl<<"DEBUG"<<endl; 
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 
*/

1011

题意:统计满足 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)(rl+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;
}


评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值