前言
好好练dp
A. Min Or Sum
水题,没有难度
题解:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
typedef long long ll;
using namespace std;
const int N = 1e5 + 10;
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
ll n;
scanf("%lld", &n);
ll sum = 0;
for (int i = 1;i<=n;i++){
ll a;
scanf("%lld", &a);
sum = (sum | a);
}
printf("%lld\n", sum);
}
return 0;
}
B. Avoid Local Maximums
找到局部最大,相邻俩局部最大改变中间的值(俩局部最大的最大值)。没有相邻的改局部最大为左右相邻两个值中最大的。(水~)
题解:
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
typedef long long ll;
using namespace std;
const int N = 2e5 + 10;
int a[N];
bool b[N];
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
b[i] = 0;
}
for (int i = 2; i < n; i++)
if (a[i - 1] < a[i] && a[i + 1] < a[i])
b[i] = 1;
int sum = 0;
for (int i = 1; i <= n; i++)
{
if (b[i])
{
sum++;
if (i + 2 <= n && b[i + 2])
{
a[i + 1] = max(a[i], a[i + 2]);
b[i] = b[i + 2] = 0;
}
else
{
a[i] = max(a[i - 1], a[i + 1]);
b[i] = 0;
}
}
}
printf("%d\n", sum);
for (int i = 1; i <= n; i++)
printf("%d ", a[i]);
printf("\n");
}
return 0;
}
C. Differential Sorting
其实不用每个相邻的三个都看,也不用找最小操作数,直接看最后三个就好。(继续水~)
题解:
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
typedef long long ll;
using namespace std;
const int N = 2e5 + 10;
int a[N];
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
if (a[n - 1] > a[n])
printf("-1\n");
else
{
if (a[n] < 0)
{
if (is_sorted(a + 1, a + n + 1))
printf("0\n");
else
printf("-1\n");
}
else
{
printf("%d\n", n - 2);
for (int i = 1; i <= n - 2; i++)
printf("%d %d %d\n", i, n - 1, n);
}
}
}
return 0;
}
D. Infinite Set
设f(x)=k(k为2的指数),那么f(2x+1)=k+1,f(4x)=k+2(位运算考虑)
当一个数eg. 3时(二进制11),23=110(二进制),23+1=111(二进制),4*3=1100(二进制)
由此观之,一个数进行位运算(x>>=1(结尾为“1”)或者x>>=2(结尾为“00”)后能够得到数组中出现过的其他数字,证明可以由这些数进行运算得来,而且它进行运算之后得数也能由那个数运算得来。删掉所有这样的数字就相当于删掉了所有之后运算重复的数字。
而dp0=1,dpi=dpi-1+dpi-2,之后的运算就好处理了。
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 2e5 + 10, mod = 1e9 + 7;
int a[N];
set<int> s;
int main()
{
int n, q;
scanf("%d %d", &n, &q);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
sort(a + 1, a + n + 1);//记得排序
//第一部分,位运算部分(追溯到最原始的值,看是否可以由小的值运算得来,删除会重复的元素)
for (int i = 1; i <= n; i++)
{
int x = a[i];
bool flag = 0;
while (x > 0)
{
if (s.count(x))
flag = 1;
if (x & 1)
x >>= 1;
else if (x & 3)
break;
else
x >>= 2;
}
if (!flag)
s.insert(a[i]);
}
//第二部分,计算每个阶段的值,方便进行dp
vector<int> cnt(30, 0), dp(q);
for (int x : s)
{
cnt[__lg(x)]++;//对数函数
}
int ans = 0;
//第三部分,dp求解
for (int i = 0; i < q; ++i)
{
if (i < 30)
{
dp[i] = cnt[i];
}
if (i >= 1)
{
dp[i] += dp[i - 1];
if (dp[i] >= mod)
{
dp[i] -= mod;
}
}
if (i >= 2)
{
dp[i] += dp[i - 2];
if (dp[i] >= mod)
{
dp[i] -= mod;
}
}
ans += dp[i];
if (ans >= mod)
{
ans -= mod;
}
}
cout << ans << endl;
return 0;
}
总结
网不好不要打cf(哭唧唧(