题目集地址 Codeforces Round #772 (Div. 2)
A Min Or Sum
题目大意:给一个长度为n的序列a,执行如下操作
用x替换
a
i
a_i
ai用y替换
a
j
a_j
aj,保证
a
i
∣
a
j
a_i|a_j
ai∣aj=x|y,
问执行任意次以上操作后整个序列的和最小是多少?
思路:对于任意的
a
i
,
a
j
a_i,a_j
ai,aj,令x=
a
i
∣
a
j
a_i|a_j
ai∣aj,都可以替换为x和0,最后将所有的数字替换过后,最终数组只剩下所有数字的或的值和0,最后的和就是所有数字的或的值
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int a[200];
void solve()
{
int n;
scanf("%d",&n);
int sum=0;
for(int i =1;i <= n;i++)
{
scanf("%d",a+i);
sum=sum|a[i];
}
cout << sum << endl;
}
int main()
{
// freopen("in.txt","r",stdin);
int t = 1;
scanf("%d",&t);
while(t--)
{
solve();
}
return 0;
}
B Avoid Local Maximums
题目大意:给定一个数组,可以将其中任意一个数字替换成1到1e9的任意值,问最少执行几次操作可以实现数组中不存在Local maximums。
关于local maximums的定义是,KaTeX parse error: Expected 'EOF', got '&' at position 12: a_i>a_{i-1}&̲&a_i>a{i+1},
a
1
和
a
n
a_1和a_n
a1和an永远不是local maximums
思路:遍历数组的值,同时进行判断,如果a[i]是一个local maximums,那么将a[i+1]修改为max(a[i],a[i+2])即可。
代码:
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e5+5;
int a[N];
void solve()
{
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i++)
{
scanf("%d",a+i);
}
int cnt=0;
if(n==2)
{
cnt=0;
}
else{
for(int i= 2;i <n;i++)
{
if(a[i]>a[i-1]&&a[i]>a[i+1])
{
if(i+2<n)
{
a[i+1]=max(a[i],a[i+2]);
}
else{
a[i+1]=a[i];
}
cnt++;
}
}
}
printf("%d\n",cnt);
for(int i = 1;i <= n;i++)
{
if(i<n)
printf("%d ",a[i]);
else
{
printf("%d\n",a[i]);
}
}
}
int main()
{
// freopen("in.txt","r",stdin);
int t = 1;
scanf("%d",&t);
while(t--)
{
solve();
}
return 0;
}
C Differential Sorting
题目大意:给一个长度为n的数组,你可以执行以下操作不超过n次:选三个数组x,y,z(
1
≤
x
<
y
<
z
≤
n
1\le x<y<z\le n
1≤x<y<z≤n),用
a
y
−
a
z
a_y-a_z
ay−az替换
a
x
a_x
ax,输出操作的次数和每次的操作。
思路:首先如果原数组就是非递减数组,那么就不需要再进行操作了。
如果原数组不是非递减数组,必须保证a[n]>0,因为如果a[n]<0,那么整个数组都必须是小于零的数,如果存在a[x]>a[y],那么就找不到一个数可以使a[y]-a[z]<a[y],因为a[z]<0,如果a[n-1]>a[n]那么也不存在z>n使得a[n]-a[z]<a[n];
后面只需要从a[n]开始倒序遍历,只要遇到a[i]>a[i+1]就执行a[i]=a[i+1]-a[n]操作即可。
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e5+5;
ll a[N];
void solve()
{
int n;
scanf("%d",&n);
bool flag=false;
for(int i = 1;i <= n;i++)
{
scanf("%lld",a+i);
if(i>1&&a[i]<a[i-1])
{
flag=true;
}
}
int cnt=0;
vector<int> ans;
ans.clear();
if(flag)
{
if(a[n]<0||a[n-1]>a[n])
{
printf("-1\n");
}
else{
for(int i = n-2;i >= 1;i--)
{
if(a[i]>a[i+1])
{
a[i]=a[i+1]-a[n];
cnt++;
ans.push_back(i);
}
}
printf("%d\n",cnt);
for(int i = 0;i < cnt;i++)
{
printf("%d %d %d\n",ans[i],ans[i]+1,n);
}
}
}
else{
printf("0\n");
}
}
int main()
{
// freopen("in.txt","r",stdin);
int t = 1;
scanf("%d",&t);
while(t--)
{
solve();
}
return 0;
}
D Infinite Set 思维+DP
题目大意:给一个长度为n的数组a。
有一个无限大的集合S,包含所有满足以下条件之一的x:
1.x=a[i]对于
1
≤
i
≤
n
1 \le i\le n
1≤i≤n
2.x=2y+1 y是S集合里的数字.
3.x=4y y是S集合里的数字
输出S集合中严格小于
2
p
2^p
2p的数的个数,结果对1e9+7取余.
思路:看到题目中2,4还有最后的结果
2
p
2^p
2p,应该想到从2进制的角度考虑(本蒟蒻没有想到)
我们用dp[i]表示大于等于
2
i
2^i
2i,小于
2
i
+
1
2^{i+1}
2i+1的数的个数,也就是数的2进制位数为i的个数。
那么对于dp[i]我们可以用dp[i-1]一步生成也可以用dp[i-2]一步生成,那么递推式如下
d
p
[
i
]
=
d
p
[
i
−
1
]
+
d
p
[
i
−
2
]
dp[i]=dp[i-1]+dp[i-2]
dp[i]=dp[i−1]+dp[i−2]
我们还需要对a数组进行去重处理,如果a[i]能生成a[j]的话,那么就不需要再统计a[j]所生成的数字的个数了。
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e5+5,maxn=1e9,mod=1e9+7;
int a[N];
int dp[N];
map<int,bool> mp;
ll sum[N];
bool judge(ll x)
{
while(x>0)
{
if(x%2)
{
x/=2;
}
else if(x%4==0)
{
x/=4;
}
else{
break;
}
if(mp.count(x))
{
return false;
}
}
return true;
}
void solve()
{
int n,p;
scanf("%d%d",&n,&p);
for(int i =1;i <= n;i++)
{
scanf("%d",a+i);
mp[a[i]]=true;
}
for(int i = 1;i <= n;i++)
{
if(judge(a[i]))
{
int p = log2(a[i]);
dp[p]++;
}
}
dp[1]=(dp[0]+dp[1])%mod;
sum[0]=dp[0];
sum[1]=(sum[0]+dp[1])%mod;
for(int i = 2;i<=p;i++)
{
dp[i]=(dp[i-1]+dp[i-2]+dp[i])%mod;
sum[i]=(dp[i]+sum[i-1])%mod;
}
cout << sum[p-1] << endl;
}
int main()
{
// freopen("in.txt","r",stdin);
int t = 1;
// scanf("%d",&t);
while(t--)
{
solve();
}
return 0;
}