CF1497D Genius
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1497D Genius相关的知识,希望对你有一定的参考价值。
题意:
n个问题从i到n编号,第i个问题给出的
c
i
=
2
i
,
t
a
g
i
,
s
i
c_i=2^i,tag_i,s_i
ci=2i,tagi,si
解决问题i后解决问题j条件是:IQ<|
c
i
−
c
j
c_i-c_j
ci−cj|,同时获得|
s
i
−
s
j
s_i-s_j
si−sj|分
问题解决得次数和顺序不受限制
一开始IQ=0,求最高可获得得分数
内存限制31.25MB,大致可以开1e7的数组
题解:
很明显动态规划,按照一般思路设dp[i][j]:上一次是第i个问题,本次是第j个问题的最大贡献。但是很明显空间不够
对于dp[][]的状态转移,当且仅当
∣
c
k
−
c
j
∣
>
∣
c
i
−
c
j
∣
|c_k-c_j|>|c_i-c_j|
∣ck−cj∣>∣ci−cj∣,可以从
d
p
i
,
j
dp_{i,j}
dpi,j转移到
d
p
j
,
k
dp_{j,k}
dpj,k
我们将这个
∣
c
i
−
c
j
∣
|c_i-c_j|
∣ci−cj∣放在图论上分析,就是有n个点,任意两点之间建边,边权为
∣
c
i
−
c
j
∣
|c_i-c_j|
∣ci−cj∣的一个无向图,我们可以在无向图商从小边权向大边权转移,这样就可以不用二维来转移,降低空间复杂度
设
d
p
i
dp_i
dpi表示最后一个问题是i的最大贡献,当我们走(i,j)这条边时,状态i可以由状态j更新,同理,状态j也可以由状态i更新,因为这是无向边。
有转移方程:
v
a
l
=
∣
s
i
,
s
j
∣
val=|s_i,s_j|
val=∣si,sj∣
t
m
p
i
=
d
p
i
tmp_i=dp_i
tmpi=dpi
t
m
p
j
=
d
p
j
tmp_j=dp_j
tmpj=dpj
d
p
i
=
m
a
x
(
d
p
i
,
t
m
p
j
+
v
a
l
)
dp_i=max(dp_i,tmp_j+val)
dpi=max(dpi,tmpj+val)
d
p
j
=
m
a
x
(
d
p
j
,
t
m
p
i
+
v
a
l
)
dp_j=max(dp_j,tmp_i+val)
dpj=max(dpj,tmpi+val)
不过问题还没完全解决,现在我们还要考虑几个问题:
- 边权一样,优先级顺序?
- 如何按照边权从小到大枚举边
因为
c
i
=
2
i
c_i=2^i
ci=2i,边权都是
∣
2
i
−
2
j
∣
|2^i-2^j|
∣2i−2j∣的形式,说明对于任意不同的(i,j),所对应的边也一定不同。也就是不会有边权一样的边
对于第二个问题,因为有空间的限制,我们不可以存下所有边然后排序。此时我们观察(i,j)权值的变化情况,假设i<j,权值二进制状态下区间[i,j-1]的位置都是1,说明当j越大时,权值越大,当j一样时,i越小权值越大
那么我们就看这样枚举点对(i,j),先枚举j,从小到大,然后枚举i,从大到小,这样枚举出来的边权保证从小到大
代码:
#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
void read(){};
template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar)
{
x= 0;
char c= getchar();
bool flag= 0;
while (c < '0' || c > '9')
flag|= (c == '-'), c= getchar();
while (c >= '0' && c <= '9')
x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();
if (flag)
x= -x;
read(Ar...);
}
template <typename T> inline void write(T x)
{
if (x < 0) {
x= ~(x - 1);
putchar('-');
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#else
startTime= clock();
freopen("data.in", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#else
endTime= clock();
printf("\\nRun Time:%lfs\\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int maxn= 5e3 + 9;
ll tag[maxn];
ll s[maxn];
ll dp[maxn];
int x[maxn][maxn];
int main()
{
//rd_test();
int t;
read(t);
while (t--) {
int n;
cin >> n;
memset(dp, 0, sizeof(dp));
for (int i= 1; i <= n; i++)
cin >> tag[i];
for (int i= 1; i <= n; i++)
cin >> s[i];
for (int j= 2; j <= n; j++) {
for (int i= j - 1; i >= 1; i--) {
if (tag[i] == tag[j])
continue;
ll tmpi= dp[i];
ll tmpj= dp[j];
ll val= abs(s[i] - s[j]);
dp[i]= max(dp[i], tmpj + val);
dp[j]= max(dp[j], tmpi + val);
}
}
ll maxx= 0;
for (int i= 1; i <= n; i++) {
maxx= max(maxx, dp[i]);
}
cout << maxx << endl;
}
//Time_test();
}
以上是关于CF1497D Genius的主要内容,如果未能解决你的问题,请参考以下文章