Codeforces Round #806 (Div. 4)
E.Mirror Grid
题意
给你一个只包含0和1的边长为n正方形网格,你可以将网格上的0转化为1或者1转化为0,使得将正方形旋转 9 0 o , 18 0 o , 27 0 o , 0 o 90^o,180^o,270^o,0^o 90o,180o,270o,0o正方形不变,问你最少的操作次数。
数据范围
1 ⩽ n ⩽ 100 1 \leqslant n \leqslant 100 1⩽n⩽100
考点
模拟,思维
思路
我们可以发现,旋转过程中原坐标为 ( x , y ) (x, y) (x,y)的网格顺时针旋转 9 0 o 90^o 90o会旋转到 ( y , n − x + 1 ) ( 下 标 从 1 开 始 ) (y, n - x + 1)(下标从1开始) (y,n−x+1)(下标从1开始),旋转四次又重新回到 ( x , y ) (x, y) (x,y)。所以我们只需要保证每个格子对应的旋转后的三个格子上的数字一样即可。
代码
void solve()
{
scanf("%d",&n);
mp.clear();
for(int i = 1; i <= n; i ++ )
scanf("%s", s[i] + 1);
int ans = 0;
for(int i = 1; i <= n; i ++ ){
for(int j = 1; j <= n; j ++ ){
if(mp.find({i, j}) == mp.end()){
int sum = 0;
int x = i, y = j;
for(int k = 1; k <= 4; k ++ ){
int newi = y, newj = n + 1 - x;
x = newi, y = newj;
mp[{newi, newj}] = 1;
if(s[newi][newj] == '1') sum ++;
}
ans += min(4 - sum, sum);
}
}
}
cout << ans << endl;
}
G. Good Key, Bad Key
题意
有n个宝箱,你需要按1~n顺序打开所有宝箱每个宝箱里面有一定数量的金币,每次开箱后能获得其中的金币,每次开箱有两种钥匙可以选择,好钥匙和坏钥匙,如果是好钥匙,你需要花费k元买钥匙。如果是坏钥匙,不需要花费购买钥匙的钱,但后面的所有的宝箱中的金币数量减半,问你开完所有箱子后你获得金币的最大价值。
考点
dp,贪心
数据范围
1 ⩽ n ⩽ 1 0 5 , 1 ⩽ k ⩽ 1 0 9 , 1 ⩽ a i ⩽ 1 0 9 1 \leqslant n \leqslant 10^5, 1 \leqslant k \leqslant 10^9, 1 \leqslant a_i \leqslant 10^9 1⩽n⩽105,1⩽k⩽109,1⩽ai⩽109
思路
我们可以发现如果选择了超过29次坏钥匙,后面的所有的金币都为0,那么后面的可以都用坏钥匙开,保证花费最小。
我们用 d p [ i ] [ j ] dp[i][j] dp[i][j]表示到第 i i i个箱子为止,一共使用了 j j j次坏钥匙的产生的最大贡献,我们可以吧集合分为两种,
- 当前宝箱用坏钥匙开 d p [ i − 1 ] [ j − 1 ] + a [ i ] / p o w 2 [ j ] dp[i - 1][j - 1] + a[i] / pow2[j] dp[i−1][j−1]+a[i]/pow2[j]
- 当前宝箱不用坏钥匙开 d p [ i − 1 ] [ j ] + a [ i ] / p o w 2 [ j ] − k dp[i - 1][j] + a[i] / pow2[j] - k dp[i−1][j]+a[i]/pow2[j]−k
- 两者取最大值即可
d p dp dp数组的初始化
本题可以赊账,所以一开始 d p dp dp数组要初始化为 − ∞ -\infty −∞
d p [ 0 ] [ 0 ] dp[0][0] dp[0][0] = 0
代码
int n, m;
int a[N];
LL dp[N][35];//开第i个盒子用了j个bad钥匙能obtain的maximum
int pow2[N];
void solve()
{
scanf("%d %d",&n, &m);
for(int i = 1; i <= n; i ++ ) scanf("%d",&a[i]);
for(int i = 0; i <= n + 1; i ++ ) for(int j = 0; j <= 30; j ++ ) dp[i][j] = -1e18;
dp[0][0] = 0;
LL ans = 0;
for(int i = 1; i <= n; i ++ )
for(int j = 0; j <= 30; j ++ ){
if(j == 0) dp[i][j] = max(dp[i - 1][0] + a[i] - m, dp[i][j]);
else{
dp[i][j] = max({dp[i - 1][j - 1] + a[i] / pow2[j], dp[i - 1][j] + a[i] / pow2[j] - m});
}
ans = max(dp[i][j], ans);
}
printf("%lld\n",ans);
}
本文解析了两道来自Codeforces竞赛的题目:E.MirrorGrid要求最少操作转换正方形网格,通过模拟旋转保持不变;G.GoodKey,BadKey涉及动态规划解决开宝箱问题,考虑好钥匙和坏钥匙的成本与收益最大化。
1088

被折叠的 条评论
为什么被折叠?



