Codeforces Round 889 (Div. 2) 题解(A~E)

A. Dalton the Teacher

思路:显然我们可以在一步操作使两个sad的学生变得happy,设有s个sad的学生,那么答案显然是 \frac{s+1}{2} 。

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
void solve(){
	int n;
	cin>>n;
	int res=0;
	for(int i=0,t;i<n;i++){
		cin>>t;
		if(t==i+1)res++;
	}
	cout<<(res+1)/2<<'\n';
	return;
}
int main(){
	ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

B. Longest Divisors Interval

思路:显然l从1开始可以得到最优解。

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
void solve(){
	ll n;
	cin>>n;
	for(int i=1;i<=n+1;i++){
		if(n%i!=0){
			cout<<i-1<<'\n';
			return;
		}
	}
	return;
}
int main(){
	ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

C1. Dual (Easy Version)

思路:我们可以发现如果数组是全非负或者全非正的,那么我们可以在最多n-1次操作使其变为符合要求的。那么我们考虑如何使其变为全非负或者全非正的,我们可以找到数组中绝对值最大的数,如果其为正,那么数组所有数加上它就变为非负的;如果其为负,那么所有数加上它就变成非正的了。此操作最多也为n-1次,所以总操作为2*n-2次,满足题意。

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
void solve(){
	int n;
	cin>>n;
	vector<int>a(n);
	int t=0;
	for(int i=0;i<n;i++)cin>>a[i];
	for(int i=0;i<n;i++)t=max(t,abs(a[i]));
	int j;
	for(int i=0;i<n;i++)if(abs(a[i])==t)j=i;
	vector<array<int,2>>res;
	if(a[j]>0){
		for(int i=0;i<n;i++){
			if(a[i]<0){
				res.push_back({i,j});
				a[i]+=a[j];
			}
		}
		for(int i=1;i<n;i++){
			if(a[i]<a[i-1]){
				res.push_back({i,j});
				a[i]+=a[j];
				if(a[i]>a[j])j=i;
			}
		}
	}
	else{
		for(int i=0;i<n;i++){
			if(a[i]>0){
				res.push_back({i,j});
				a[i]+=a[j];
			}
		}
		for(int i=n-2;i>=0;i--){
			if(a[i]>a[i+1]){
				res.push_back({i,j});
				a[i]+=a[j];
				if(a[i]<a[j])j=i;
			}
		}
	}
	cout<<res.size()<<endl;
	for(auto [x,y]:res)cout<<x+1<<" "<<y+1<<'\n';
	return;
}
int main(){
	ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

C2. Dual (Hard Version)

思路:现在我们考虑如何优化使数组变为非负或者非正的操作次数,首先我们可以考虑负数和正数的数量,假设负数多,我们可以考虑都变为负,使用5次操作将一个负数倍增,使其变为一定<-20,那么操作数可能是9+5+19=33次还是不满足题意;那么我们再考虑到C1中的操作,假设绝对值最大的数为正数,设负数的数量为x,那么操作数是x+19,显然当x<13时满足;当x>=13时我们就可以用上述的第一种办法,那么操作数最大为7+5+19满足了题意。

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
void solve(){
	int n;
	cin>>n;
	vector<int>a(n);
	for(int i=0;i<n;i++)cin>>a[i];
	int j=0;
	for(int i=0;i<n;i++)if(abs(a[i])>abs(a[j]))j=i;
	vector<array<int,2>>res;
	bool ok=1;
	if(a[j]>0){
		int cnt=0;
		for(int i=0;i<n;i++){
			if(a[i]<0){
				cnt++;
			}
		}
		if(cnt<=12){
			for(int i=0;i<n;i++){
				if(a[i]<0){
					res.push_back({i,j});
					a[i]+=a[j];
				}
			}
		}
		else{
			ok=0;
			j=0;
			for(int i=0;i<n;i++){
				if(a[i]<a[j])j=i;
			}
			for(int i=0;i<5;i++){
				a[j]+=a[j];
				res.push_back({j,j});
			}
			for(int i=0;i<n;i++){
				if(a[i]>0){
					res.push_back({i,j});
					a[i]+=a[j];
				}
			}
		}
	}
	else{
		int cnt=0;
		for(int i=0;i<n;i++){
			if(a[i]>0){
				cnt++;
			}
		}
		if(cnt<=12){
			ok=0;
			for(int i=0;i<n;i++){
				if(a[i]>0){
					res.push_back({i,j});
					a[i]+=a[j];
				}
			}
		}
		else{
			j=0;
			for(int i=0;i<n;i++){
				if(a[i]>a[j])j=i;
			}
			for(int i=0;i<5;i++){
				a[j]+=a[j];
				res.push_back({j,j});
			}
			for(int i=0;i<n;i++){
				if(a[i]<0){
					res.push_back({i,j});
					a[i]+=a[j];
				}
			}
		}
	}
	if(ok){
		for(int i=1;i<n;i++){
			if(a[i]<a[i-1]){
				res.push_back({i,j});
				a[i]+=a[j];
				if(a[i]>a[j])j=i;
			}
		}
	}
	else{
		for(int i=n-2;i>=0;i--){
			if(a[i]>a[i+1]){
				res.push_back({i,j});
				a[i]+=a[j];
				if(a[i]<a[j])j=i;
			}
		}
	}
	cout<<res.size()<<endl;
	for(auto [x,y]:res)cout<<x+1<<" "<<y+1<<'\n';
	return;
}
int main(){
	ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}
 

D. Earn or Unlock

思路:首先我们可以得出如果我们可以刚好到达i,那么此时的答案就是前缀和s[i] - i + 1。那么我们考虑如何得到是否可以恰好到达 i 。类似于背包问题容量为 i ,时间复杂度是n*n。考虑如何优化此问题,我们可以想到使用 bitset 优化得到一个集合储存了前 i 个点可到达的点的集合。但是我们要考虑到后 n+1 ~ 2*n 也是可到达的,我们考虑进去即可。

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
void solve(){
	int n;
	cin>>n;
	vector<int>a(n+1);
	vector<ll>s(n+1);
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i];
	bitset<200005>b;
	ll res=0;
	b[1]=1;
	for(int i=1;i<=n;i++){
		b|=(b<<a[i]);		
		if(b[i]){
			res=max(res,s[i]-i+1);
			b[i]=0;
		}
	}	
	for(int i=n+1;i<=2*n;i++){
		if(b[i])res=max(res,s[n]-i+1);
	}
	cout<<res<<endl;
	return;
}
int main(){
	ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
	int t=1;
	while(t--){
		solve();
	}
	return 0;
}

E. Expected Destruction

思路:我们可以将题意转化为从1到 m+1 的数轴上有n个点,每个点可以向前走一格,当两个相遇时汇合成一个点,那么我们也可以看成当 x 撞到 x+1 时,x+1 这个点消失,那么对于 ai 和 ai+1 两个点来说,ai 需要走多少步撞到下一个点的期望是独立与其他点的。所以我们可以分别求解每个点所要走步数的期望,设 dp_{i,j} 为从 i 走到 j 点 i 所需走的步数。那么dp_{i,j}=(dp_{i+1,j}+1+dp_{i,j+1})*\frac{1}{2},我们在最后再加上一个 m+1 这个点即可以得到答案。

#include <bits/stdc++.h>
using namespace std;
using ll=long long;

template<class T>
constexpr T power(T a, ll b) {
    T res = 1;
    for (; b; b /= 2, a *= a) {
        if (b % 2) {
            res *= a;
        }
    }
    return res;
}

constexpr ll mul(ll a, ll b, ll p) {
    ll res = a * b - ll(1.L * a * b / p) * p;
    res %= p;
    if (res < 0) {
        res += p;
    }
    return res;
}
template<ll P>
struct MLong {
    ll x;
    constexpr MLong() : x{} {}
    constexpr MLong(ll x) : x{norm(x % getMod())} {}
    
    static ll Mod;
    constexpr static ll getMod() {
        if (P > 0) {
            return P;
        } else {
            return Mod;
        }
    }
    constexpr static void setMod(ll Mod_) {
        Mod = Mod_;
    }
    constexpr ll norm(ll x) const {
        if (x < 0) {
            x += getMod();
        }
        if (x >= getMod()) {
            x -= getMod();
        }
        return x;
    }
    constexpr ll val() const {
        return x;
    }
    explicit constexpr operator ll() const {
        return x;
    }
    constexpr MLong operator-() const {
        MLong res;
        res.x = norm(getMod() - x);
        return res;
    }
    constexpr MLong inv() const {
        assert(x != 0);
        return power(*this, getMod() - 2);
    }
    constexpr MLong &operator*=(MLong rhs) & {
        x = mul(x, rhs.x, getMod());
        return *this;
    }
    constexpr MLong &operator+=(MLong rhs) & {
        x = norm(x + rhs.x);
        return *this;
    }
    constexpr MLong &operator-=(MLong rhs) & {
        x = norm(x - rhs.x);
        return *this;
    }
    constexpr MLong &operator/=(MLong rhs) & {
        return *this *= rhs.inv();
    }
    friend constexpr MLong operator*(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res *= rhs;
        return res;
    }
    friend constexpr MLong operator+(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res += rhs;
        return res;
    }
    friend constexpr MLong operator-(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res -= rhs;
        return res;
    }
    friend constexpr MLong operator/(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res /= rhs;
        return res;
    }
    friend constexpr std::istream &operator>>(std::istream &is, MLong &a) {
        ll v;
        is >> v;
        a = MLong(v);
        return is;
    }
    friend constexpr std::ostream &operator<<(std::ostream &os, const MLong &a) {
        return os << a.val();
    }
    friend constexpr bool operator==(MLong lhs, MLong rhs) {
        return lhs.val() == rhs.val();
    }
    friend constexpr bool operator!=(MLong lhs, MLong rhs) {
        return lhs.val() != rhs.val();
    }
};

template<>
ll MLong<0LL>::Mod = ll(1E18) + 9;

template<int P>
struct MInt {
    int x;
    constexpr MInt() : x{} {}
    constexpr MInt(ll x) : x{norm(x % getMod())} {}
    
    static int Mod;
    constexpr static int getMod() {
        if (P > 0) {
            return P;
        } else {
            return Mod;
        }
    }
    constexpr static void setMod(int Mod_) {
        Mod = Mod_;
    }
    constexpr int norm(int x) const {
        if (x < 0) {
            x += getMod();
        }
        if (x >= getMod()) {
            x -= getMod();
        }
        return x;
    }
    constexpr int val() const {
        return x;
    }
    explicit constexpr operator int() const {
        return x;
    }
    constexpr MInt operator-() const {
        MInt res;
        res.x = norm(getMod() - x);
        return res;
    }
    constexpr MInt inv() const {
        assert(x != 0);
        return power(*this, getMod() - 2);
    }
    constexpr MInt &operator*=(MInt rhs) & {
        x = 1LL * x * rhs.x % getMod();
        return *this;
    }
    constexpr MInt &operator+=(MInt rhs) & {
        x = norm(x + rhs.x);
        return *this;
    }
    constexpr MInt &operator-=(MInt rhs) & {
        x = norm(x - rhs.x);
        return *this;
    }
    constexpr MInt &operator/=(MInt rhs) & {
        return *this *= rhs.inv();
    }
    friend constexpr MInt operator*(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res *= rhs;
        return res;
    }
    friend constexpr MInt operator+(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res += rhs;
        return res;
    }
    friend constexpr MInt operator-(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res -= rhs;
        return res;
    }
    friend constexpr MInt operator/(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res /= rhs;
        return res;
    }
    friend constexpr std::istream &operator>>(std::istream &is, MInt &a) {
        ll v;
        is >> v;
        a = MInt(v);
        return is;
    }
    friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a) {
        return os << a.val();
    }
    friend constexpr bool operator==(MInt lhs, MInt rhs) {
        return lhs.val() == rhs.val();
    }
    friend constexpr bool operator!=(MInt lhs, MInt rhs) {
        return lhs.val() != rhs.val();
    }
};

template<>
int MInt<0>::Mod = 998244353;

template<int V, int P>
constexpr MInt<P> CInv = MInt<P>(V).inv();

constexpr int P = 1000000007;
using Z = MInt<P>;

int main(){
	ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
	int n,m;
	cin>>n>>m;
	vector<int>a(n+1);
	for(int i=0;i<n;i++)cin>>a[i];
	a[n]=m+1;
	vector<vector<Z>>dp(m+1,vector<Z>(m+1,0));
	for(int i=m-1;i>=0;i--){
		for(int j=m;j>=i;j--){
			if(i==j){
				dp[i][j]=0;
			}
			else{
				if(j==m){
					dp[i][j]=dp[i+1][j]+1;
				}
				else dp[i][j]=CInv<2,P>*(dp[i+1][j]+1+dp[i][j+1]);
			}
		}

	}
	Z res=0;
	for(int i=1;i<=n;i++){
		res+=dp[a[i-1]-1][a[i]-1];
	}
	cout<<res<<endl;
	return 0;
}
 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值