链接:2020-2021 Winter Petrozavodsk Camp, Belarusian SU Contest (XXI Open Cup, Grand Prix of Belarus)
有 n n n 个路由器,第 i i i 个路由器的的频度是 f i f_i fi ,假设有 k k k 个路由器 i 1 , i 2 , … , i k i_1, i_2, …, i_k i1,i2,…,ik 开着,那么此时的网络安全系数的值是 ∑ j = 1 k a i j \sum_{j = 1}^k a_{i_j} ∑j=1kaij 。问网络安全系数的最大值是?
背包dp, d p i , j dp_{i, j} dpi,j表示处理到 i i i ,打开 j j j 个的最大安全系数。
处理到 f i f_i fi 时的转移方程式:
d p i , j = m a x ( d p i − 1 , j , d p p r e , j − 1 + f p r e & f i ) dp_{i, j} = max(dp_{i - 1, j}, dp_{pre, j - 1} + f_{pre} \& f_i) dpi,j=max(dpi−1,j,dppre,j−1+fpre&fi)
这里的 p r e pre pre 表示上一个被选中的数。但是数据范围 1 e 6 1e6 1e6 ,所以改成滚动数组减少一维。
最终的转移方程:( p r e pre pre 的可能值可以通过对 a i a_i ai 逐位运算进行枚举,这个在代码中有所体现)
d p i = m a x ( d p i , d p p r e + f p r e & f i ) dp_i = max(dp_i, dp_{pre} + f_{pre} \& f_i) dpi=max(dpi,dppre+fpre&fi)
#include
#define INF 0x3f3f3f3f
#define PI acos(-1)
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
const int N = 2e6 + 9;
const ll MOD = 1e9 + 7;
ll dp[N];
ll a[N];
ll pre[N];
int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%lld", a + i);
}
ll ans = 0;
for(int i = 1; i <= n; i++)
{
for(int j = 0; j <= 50; j++)
{
if(a[i] & (1ll << j))
{
dp[i] = max(dp[i], dp[pre[j]] + (a[pre[j]] & a[i]));
pre[j] = i;
}
}
ans = max(ans, dp[i]);
dp[i] = ans;
}
printf("%lld\n", ans);
return 0;
}
A有 n n n 个牌, B有 m m m 个牌,其中一些是红的一些是黄的。进行 k k k 次交换,第 i i i 次A给B s i s_i si 张牌,B再在当前的所有牌中给A s i s_i si 张牌。最终得分为A的黄牌数-B的红牌数的绝对值,A要使之尽可能大,B要使之尽可能小。问最终得分?
就是A的|初始黄牌数-B的初始红牌数|,可以证明之后其实怎么改都是不会改变这两者差的绝对值。
#include
#define INF 0x3f3f3f3f
#define PI acos(-1)
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
const int N = 2e6 + 9;
const ll MOD = 1e9 + 7;
int main()
{
int n, m, k;
scanf("%d%d%d", &n, &m, &k);
int ans = 0;
for(int i = 0, tmp; i < n; i++)
{
scanf("%d", &tmp);
if(tmp == 0)
ans++;
}
for(int i = 0, tmp; i < m; i++)
{
scanf("%d", &tmp);
if(tmp)
ans--;
}
printf("%d\n", abs(ans));
return 0;
}
给定数字 n n n ,要求你构造长度 k ≥ ⌈ 2 3 ⋅ n ⌉ k \geq \lceil \frac{2}{3} · n \rceil k≥⌈32⋅n⌉ 的序列 a a a ,使之满足以下条件:
设 g i = g c d ( a i , a i + 1 ) g_i = gcd(a_i, a_{i + 1}) gi=gcd(ai,ai+1) ,我们又要使 a i a_i ai 的值尽可能小这样才能增加长度,所以必然有 g i ∗ g i + 1 = a i + 1 g_i * g_{i + 1} = a_{i + 1} gi∗gi+1=ai+1。由此我们得到:
g c d ( a i , a i + 1 ) = g i a i = g i − 1 ∗ g i a i + 1 = g i ∗ g i + 1 gcd(a_i, a_{i + 1}) = g_i\\a_i = g_{i - 1} * g_i\\ a_{i + 1} = g_i * g_{i + 1} gcd(ai,ai+1)=giai=gi−1∗giai+1=gi∗gi+1
显然, g i − 1 g_{i - 1} gi−1 和 g i + 1 g_{i + 1} gi+1 要互质。根据这个性质去构造即可。
#include
#define INF 0x3f3f3f3f
#define PI acos(-1)
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
const int N = 1e6 + 9;
const ll MOD = 1e9 + 7;
ll gcd[N];
int main()
{
ll n;
scanf("%lld", &n);
gcd[0] = 1;
gcd[1] = 2;
gcd[2] = 3;
int kmin = 2.0 / 3.0 * sqrt((double)n) + 1;
for(int k = 3; k < kmin; k++)
{
ll x = gcd[k - 1] + 1;
while(__gcd(gcd[k - 2], x) != 1)
{
x++;
}
gcd[k] = x;
}
printf("%d\n1", kmin);
for(int i = 0; i < kmin - 1; i++)
{
printf(" %lld", gcd[i] * gcd[i + 1]);
}
printf("\n");
return 0;
}