2022.11.22

2022.11.22

很不对劲。

YCC 个大 SB。

感觉状态远不如在日照的时候。

YCC 种草世界杯?

明明啥也看不懂,但是还很想看。

装箱

能很显然的看出是个 dp。

/*
Date:2022.11.22
Source:模拟赛 
knowledge: f[i] 表示前i个的最小花费 
*/
#include <cstdio>
#include <iostream>
#include <cstring>
#define orz cout << "AK IOI" << "\n";
#define int long long  

using namespace std;
const int maxn = 2e4 + 10;

inline int read()
{
    int x = 0, f = 1;  char ch = getchar();
    while(ch > '9' || ch < '0') {if(ch == '-') f = -1; ch = getchar();}
    while(ch <= '9' && ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    return x * f;
}
inline void print(int X)
{
    if(X < 0) X = ~(X - 1), putchar('-');
    if(X > 9) print(X / 10);
    putchar(X % 10 ^ '0');
    return ;
}
inline int Max(int a, int b){
    return a > b ? a : b;
}
inline int Min(int a, int b){
    return a < b ? a : b;
}
int n, m, k, a[maxn], f[maxn];
signed main() 
{
    n = read(), m = read(), k = read();
    for(int i = 1; i <= n; i++) f[i] = 1e18;
    for(int i = 1; i <= n; i++) a[i] = read();
    for(int i = 1; i <= n; i++) 
    { 
        int maxx = -1e18, minn = 1e18;
        for (int j = i; j <= min(n, i + m - 1); j++) 
        {
            maxx = Max(maxx, a[j]);
            minn = Min(minn, a[j]);
            f[j] = min(f[j], f[i - 1] + (j - i + 1) * (maxx - minn) + k);
        }
    }
    print(f[n]);
    return 0;
}

二进制

30pts 爆搜

/*
Date:
Source:
knowledge:
*/
#include <cstdio>
#include <iostream>
#define orz cout << "AK IOI" << "\n";
#define int long long

using namespace std;
const int maxn = 1e6 + 10;

inline int read()
{
    int x = 0, f = 1;  char ch = getchar();
    while(ch > '9' || ch < '0') {if(ch == '-') f = -1; ch = getchar();}
    while(ch <= '9' && ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    return x * f;
}
inline void print(int X)
{
    if(X < 0) X = ~(X - 1), putchar('-');
    if(X > 9) print(X / 10);
    putchar(X % 10 ^ '0');
    return ;
}
inline int Max(int a, int b){
    return a > b ? a : b;
}
inline int Min(int a, int b){
    return a < b ? a : b;
}
int n;
char a[maxn];
namespace sub1{
    int power[10], ans = 0x3f3f3f3f, num;
    void init()
    {
        power[0] = 1;
        for(int i = 1; i <= 10; i++) power[i] = power[i - 1] * 2;
    }
    void dfs(int tot, int now, int res)
    {
        if(now == n) 
        {
            if(tot == num) ans = min(ans, res); 
            return ;
        }    
        dfs(tot + power[now], now + 1, res + 1);
        dfs(tot - power[now], now + 1, res + 1);
        dfs(tot, now + 1, res);
    }
    void main()
    {
        init();
        num = 0;
        for(int i = 1; i <= n; i++) if((int)a[i] == 49) num = num + power[n - i];
        dfs(0, 0, 0);
        print(ans);
    }
}
signed main()
{
    //freopen("twobit.in", "r", stdin); 
    //freopen("twobit.out", "w", stdout);
    n = read();
    cin >> a + 1; sub1::main();
    //fclose(stdin);
    //fclose(stdout);
    return 0;
}

简化一下题意只有两种操作,花费 1 翻转一位, 花费 2 反转一段。

发现其中的性质。

连续两个 0 会使答案前后分别考虑

类似10101010 的情况用操作 1 更优,

其他情况运用操作 2 然后对 0 的操作位置进行操作 1 会更优。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#define M 1000100
#define ll long long
using namespace std;

int read() {
    int nm = 0, f = 1;
    char c = getchar();
    for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0';
    return nm * f;
}

char s[M];
int a[M], sum[M], n, f[M], sta[M], tp;
int main() {
    freopen("twobit.in", "r", stdin), freopen("twobit.out", "w", stdout);
    n = read();
    scanf("%s", s + 1);
    for(int i = 1; i <= n; i++) a[i] = s[n - i + 1] - '0', sum[i] = sum[i - 1] + (a[i] == 0);
    if(n <= 300) {
        f[0] = 0;
        for(int i = 1; i <= n; i++) {
            f[i] = f[i - 1] + a[i];
            for(int j = 1; j < i; j++) f[i] = min(f[i], f[j - 1] + 2 + sum[i] - sum[j - 1]);
        }
        cout << f[n] << "\n";
    } else {
        int ans = n - sum[n], tmp = 0;
        int now = 1;
        while(1) {
            while(!a[now] && now <= n) now++;
            tp = 0;
            if(now > n) break;
            while(a[now] || a[now + 1]) sta[++tp] = now++;
            tmp += min(tp - (sum[sta[tp]] - sum[sta[1] - 1]), 2 + sum[sta[tp]] - sum[sta[1] - 1]);
        }
        ans = min(ans, tmp);
        cout << ans << "\n";
    }
    return 0;
}

摆!

posted @ 2022-11-22 22:56  _程门立雪  阅读(28)  评论(1编辑  收藏  举报