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