Codeforces Round #760 (div. 3)

A

解个三元一次方程

rep(i,1,7) cin>>a[i];
sort(a+1,a+8);
cout<<a[1]<<' '<<a[2]<<' '<<a[7]-a[1]-a[2]<<'\n';

B

尾首相同加后t[1],否则加上整个t,不足补a

                string s,t,res,d;
		cin>>n>>s;
		res+=s;
		rep(i,1,n-3)
		{
			cin>>t;
			
			if(t[0]==s[1])
				res +=t[1];
			else res+= t;
			s = t;
		}
		if(res.size()<n)res+='a';
		cout<<res<<endl;

C

对奇数列和偶书列取最小公因数,分别尝试是否能行,不行取0;

        cin>>n; int a1=0,b1=0;
        rep(i,1,n){
            cin>>c[i];
            if(i&1) a[a1++] = c[i];
            else b[b1++] = c[i];
        }
        ll ma = maxgysarray(a,a1);
        ll mb = maxgysarray(b,b1);
        //cout<<ma<<' '<<mb<<endl;
        int fa = 0,fb = 0;
        rep(i,1,n){
            if(i&1){
                if(c[i]%mb==0) fa = 1;
            }
            else if(c[i]%ma==0) fb = 1;
        }
        //cout<<fg<<fb<<endl;
        if(!fa) cout<<mb<<endl;
        else if(!fb) cout<<ma<<endl;
        else cout<<0<<endl;

D

排序后取最后2*k个,令i=n-k,j = n;从后往前res += i/j即可

        cin>>n>>k;
        rep(i,1,n) cin>>a[i];
        sort(a+1,a+n+1);
        int i = n-k,j = n;
        int res = 0;
        while(k--)
        {
            res+=a[i--]/a[j--];
        }
    
        for(;k<=i;k++) res+=a[k];
        cout<<res<<endl;

E

公式推导(高斯是不可能的):bi - bi-1 = \(\Sigma\)ai - n*ai

\(\Sigma\)ai (n+1)n/2 = \(\Sigma\)bi

		cin>>n; ll sum = 0;
		
		rep(i,1,n) cin>>a[i],sum += a[i];
		
		bool ok  = 1;
		
		if(sum%((n+1)*n/2)) ok = 0;
		
		sum/=((n+1)*n/2);
		
		rep(i,1,n)
		{
			int j = i-1;
			if(!j) j = n;
			ll ca = sum - a[i]+a[j];
			if(ca%n) ok = 0;
			
			b[i] = ca/n;
			
			if(b[i]<=0) ok = 0;
                }
                if(ok)
		{
			cout<<"Yes\n";
			rep(i,1,n) cout<<b[i]<<' ';
			cout<<endl;
		}
		else cout<<"No\n";

F

新加入的可能结果二进制必然首尾是1,逆推dfs一下,有环剪下枝

ll reverse(ll x)
{
	int cnt = 0;
	for (; x; x /= 2)
		a[++cnt] = x & 1;
	ll y = 0;
	for(int i = 1;i<=cnt; i++)
		y = y*2 +a[i];
	return y;
}

bool dfs(ll x)
{
	if(!x) return 0;
	if(s.find(x)!=s.end()) return 0;
	if(x==x1||x== x2) return 1;
	s.insert(x);
	
	if(x&1)
	{
		if(reverse(x)!=x &&dfs(reverse(x)))
			return 1;
		int cnt = 0;
		for (; x; x /= 2)
		a[++cnt] = x & 1;
	
		if(cnt>1 && a[1] && a[2])
		{
			ll z = 0;
			rep(i,2,cnt) z = z*2 + a[i];
			if(dfs(z)) return 1;
		}
	}
	return 0;
}

int main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>x>>y;
	if(x==y)
	{
		puts("Yes"); return 0;
	}
	x1 = reverse(x*2+1);
	x2 = reverse(x*2);
	if(dfs(y)) puts("Yes");
	else puts("No");
    
    return 0;
}

E(搬运)

题意

Monocarp初始拥有一堆物品,a数组表示它的价值,ai表示物品i的价值。有另外有一堆不属于他的物品,一个数组b表示,表示第i个物品价值为bi。

对于一个固定的k,Monocarp每次可以拿自己拥有的物品去交换,价值为x的物品,可以交换到价值不高于x + k的物品。

现在给定q组询问,每次一个k,问Monocarp能得到的物品价值最多为多少。

题解:

对于一个固定的k,我们把两堆物品合并,然后将价值相差小于等于k的分在同一组。如果这组有x个物品本来属于a,则最优显然是交换到本组价值最高的x个物品。

所以,我们可以让k从小到大排序,从小到大合并差值小于k的组(用并查集),维护组中a物品数,以及组中前x个的和(这个可以通过前缀和得到)。

每次两个组g1, g2合并,g2中物品价值大于g1,则价值改变就是g1中原先取前x个,现在要在g2中取最优的几个(在原先g2中的取完后的前x个)。

我们也可以采用在线做法,让组间按照差值(就是排序后相邻物品价值差)从小到大合并,记录每次合并后的最大价值。查询的时候,二分到到最后一个大于等于k的位置,获取合并后的价值

#include <bits/stdc++.h>

using namespace std;

#define forn(i, n) for(int i = 0; i < int(n); i++) 

const int N = 400 * 1000 + 13;

int n, m, k;
int a[N], b[N];
int q[N];

int p[N];
multiset<int> wst[N], bst[N];
long long sum;

int getp(int a){
	return a == p[a] ? a : p[a] = getp(p[a]);
}

void unite(int a, int b){
	a = getp(a), b = getp(b);
	if (wst[a].size() + bst[a].size() < wst[b].size() + bst[b].size()) swap(a, b);
	for (auto it : wst[b])
		wst[a].insert(it);
	for (auto it : bst[b])
		bst[a].insert(it);
	wst[b].clear();
	bst[b].clear();
	while (!bst[a].empty() && !wst[a].empty() && *bst[a].begin() < *wst[a].rbegin()){
		sum -= *bst[a].begin();
		sum += *wst[a].rbegin();
		bst[a].insert(*wst[a].rbegin());
		wst[a].insert(*bst[a].begin());
		bst[a].erase(bst[a].begin());
		wst[a].erase(--wst[a].end());
	}
	p[b] = a;
}

long long ans[N];

struct event{
	int x, t, i;
};

int main() {
	scanf("%d%d%d", &n, &m, &k);
	forn(i, n)
		scanf("%d", &a[i]);
	forn(i, m)
		scanf("%d", &b[i]);
	forn(i, k)
		scanf("%d", &q[i]);
	vector<pair<int, int>> tot;
	forn(i, n) tot.push_back({a[i], 1});
	forn(i, m) tot.push_back({b[i], 0});
	sort(tot.begin(), tot.end());
	sum = accumulate(a, a + n, 0ll);
	forn(i, n + m){
		p[i] = i;
		wst[i].clear();
		bst[i].clear();
		if (tot[i].second) bst[i].insert(tot[i].first);
		else wst[i].insert(tot[i].first);
	}
	vector<event> ev;
	forn(i, n + m - 1) ev.push_back({tot[i + 1].first - tot[i].first, 0, i});
	forn(i, k) ev.push_back({q[i], 1, i});
	sort(ev.begin(), ev.end(), [](const event &a, const event &b){
		if (a.x != b.x) return a.x < b.x;
		return a.t < b.t;
	});
	for (auto it : ev){
		if (it.t == 0)
			unite(it.i, it.i + 1);
		else
			ans[it.i] = sum;
	}
	forn(i, k) printf("%lld\n", ans[i]);
}
posted @ 2021-12-15 14:35  InsiApple  阅读(84)  评论(0)    收藏  举报