• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
nannandbk
博客园    首页    新随笔    联系   管理    订阅  订阅
Codeforces Round 888 (Div. 3)DEF

Codeforces Round 888 (Div. 3)DEF

D. Prefix Permutation Sums

题意:给你一个长度为 \(n - 1\) 的数组,是否能找出一个长度为 \(n\) 的排列,求出这个排列的前缀和,去掉前缀和数组的任意一个元素之后和原来的数组相等。

例如 \([6, 8, 12, 15]\),可以是排列 \([1, 5, 2, 4, 3]\) 的前缀和 \([1, 6, 8, 12, 15]\) 去掉元素 \(1\)。

思路:维护差分数组,记录已经有了的,还需要的元素和额外的元素。最后去check是否满足。

因为只删除了一个元素,所以如果额外的元素大于1了肯定是不对的(需要的元素(如果有的的话是2个)一定加起来等于这一个额外的)。当然也有可能删除的是最后一个,那就不存在额外的元素,所以如果没有额外的元素也是正确的。

// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
ll a[N],d[N];
int main()
{
    ios::sync_with_stdio(false);   cin.tie(nullptr), cout.tie(nullptr);
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        map<ll,bool>hav;

        for(int i = 1;i < n; i++)
            cin>>a[i];
        for(int i = 1;i < n; i++)
            d[i] = a[i]-a[i-1];
        // for(int i = 1;i < n; i++)
        //     cout<<d[i]<<" ";
        // cout<<"\n";
        vector<ll>exa,need;
        for(int i = 1;i < n; i++)
        {
            if(d[i]>=1&&d[i]<=n&&!hav[d[i]])
                hav[d[i]] = true;
            else{
                exa.push_back(d[i]);
            }
        }
        if(exa.empty())
        {
            cout<<"YES\n";
            continue;
        }
        if(exa.size()>1)
        {
            cout<<"NO\n";
            continue;
        }
        for(int i = 1;i <= n; i++)
        {
            if(hav[i])continue;
            need.push_back(i);
        }
        // cout<<"need: ";
        // for(auto x : need)
        //     cout<<x<<" ";
        // cout<<"\n";
        // cout<<"exa: ";
        // for(auto x : exa)
        //     cout<<x<<" ";
        // cout<<"\n";
        if(need.size()>2)cout<<"NO\n";
        else{
            if(need.size()==0)cout<<"YES\n";
            else if(need.size()==1&&exa.size()==0)cout<<"YES\n";
            else{
                if(need.size()==2&&exa.size()==1){
                    if(exa[0]==need[0]+need[1])cout<<"YES\n";
                    else cout<<"NO\n";
                }else cout<<"NO\n";
            }
        }

        // if(need.size()==2&&(exa[0]==need[0]+need[1]))
        //     cout<<"YES\n";
        // else cout<<"NO\n";
    }   
    return 0;
}

E.Nastya and Potions

题意:炼金术士 Nastya 很喜欢合成药水。现有 $ n $ 种药水,第 $ i $ 种药水可以用 $ c_i $ 个金币买入。

任何一种药水的合成方案都不超过 $ 1 $ 种。在合成某种药水的过程中,作为原料的药水将会被完全消耗。任何药水都不能直接或间接合成它本身。

作为一个经验老道的炼金术士,Nastya 已经可以无限制地获得 $ p_1, p_2, \dots, p_k $ 这 $ k $ 种药水,可是她却没法决定接下来要合成哪些药水。于是,她求助于你。对于 $ 1 \le i \le n $,她需要你求出获得第 $ i $ 种药水所需的最少的金币数。

思路:记忆化搜索+dp

// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int n,k,c[N];
bool hav[N];
vector<int>e[N];
ll dp[N],ans[N];
ll dfs(int x)
{
    if(hav[x])return 0ll;
    ll &res = dp[x];
    if(res!=-1)return res;
    res = c[x];
    if(e[x].size())
    {
        ll tmp = 0;
        for(auto y : e[x])
            tmp += dfs(y);
        res = min(res,tmp);
    }
    return res;
}

int main()
{
    ios::sync_with_stdio(false);   cin.tie(nullptr), cout.tie(nullptr);
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n>>k;
        for(int i = 1;i <= n; i++)
            cin>>c[i],hav[i] = 0,dp[i] = -1;
        for(int i = 1;i <= k; i++)
        {
            int x; cin>>x;
            hav[x] = true;
        }

        for(int i = 1;i <= n; i++)
        {
            int m; cin>>m;
            e[i].clear();
            for(int j = 1;j <= m; j++)
            {
                int x; cin>>x;
                e[i].push_back(x);
            }
        }
        for(int i = 1;i <= n; i++)
        {
            cout<<dfs(i)<<" ";
        }
        cout<<"\n";
    }
    return 0;
}

F.Lisa and the Martians

题意:给定长度为 \(n\) 的序列 \(a\) 和一个正整数 \(k\),保证 \(0\leq a_i< 2^k\)。求满足 \(0\leq x<2^k\) 且 \(i\neq j\) 的三元组 \((i,j,x)\) 使得 \((a_i\oplus x)\operatorname{and}(a_j\oplus x)\) 最大。如果有多组符合要求的输出任意一组即可。

多组数据。

思路:对于两个数的每一位进行考虑。

设两个数的同一个位置的值分别为\(u,v\)

  • 当\(u = 1,v = 1\),此时\(x\)这一位取\(0\),使得\(\&\)之后为\(1\)
  • 当\(u = 0,v = 0\),此时\(x\)这一位取\(1\),使得\(\&\)之后为\(1\)
  • 当\(u\ne v\)时,无论\(x\)怎么取结果都是\(0\)。

为了尽可能达到最大值,高位尽可能相同。我们知道两个数越接近高位的数越相同。那么我们排序之后在相邻两个数之间考虑就行了。注意结果可能是0,maxx初始化为-1。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
array<int,2>a[N];
bool cmp(array<int,2>a,array<int,2>b)
{
	return a[0]>b[0];
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n,k;
		cin>>n>>k;
		for(int i = 1;i <= n; i++)
		{
			cin>>a[i][0];
			a[i][1] = i;
		}
		sort(a+1,a+1+n);
		ll maxx = -1,pos1 = 0,pos2 = 0,tt = 0;
		for(int i = 1;i < n; i++)
		{
			int x = a[i][0],y = a[i+1][0];
			ll w = 0,t = 0;
			for(int j = k-1;j >= 0;j--)
			{
				if(((x>>j)&1)==((y>>j)&1))
				{
					w |= (1<<j);
					if(((x>>j)&1)==0)
						t |= (1<<j);
				}
			}
			if(w>maxx)
				pos1 = a[i][1],pos2 = a[i+1][1],tt = t,maxx = w;
		}
		cout<<pos1<<" "<<pos2<<" "<<tt<<"\n";
	}
	return 0;
}
posted on 2023-10-04 12:35  nannandbk  阅读(42)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3