Daliy Algorithm (简单dp,简单构造)-- day 83

Nothing to fear


种一棵树最好的时间是十年前,其次是现在!

那些你早出晚归付出的刻苦努力,你不想训练,当你觉的太累了但还是要咬牙坚持的时候,那就是在追逐梦想,不要在意终点有什么,要享受路途的过程,或许你不能成就梦想,但一定会有更伟大的事情随之而来。 mamba out~

2020.5.20


人一我十,人十我百,追逐青春的梦想,怀着自信的心,永不言弃!

Game With Array

首先通过观察此题应该存在一种比较取巧的方案去构造数组,不然会十分麻烦,所以我们,尝试利用特殊值1去构造序列

假设对于数据
3 8
我们尝试构造数组为 1 1 6
我们尝试寻找子序列所能够组合出来的区间和
所有序列中为1的元素可以组合为
区间一:[0,n-1] 即n-1个1
区间二:[s-n+1,s]
我们此时只需对比两个区间是否能连在一起即可
如果不能连在一起说明总是能够找到一个数 k 使得
所有子序列的和既不等于 k 也不等于 s - k

对于以上例子:3 8
区间一:[0,2]
区间二:[6,8]
故我们总能够在[n , s-1]中间找到一个 K 使得满足题目要求

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <cassert>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define lowbit(x) (x & -x)
using namespace std;
typedef long long ll;
const int MAX = 0x7ffffff;
int t;

void slove()
{
    int n , s;
    cin >> n >> s;
    if(n == 1)
    {
        if(s == 1)
        {
            cout << "NO" << endl;
            return;
        }else {
            cout << "YES" << endl;
            cout << s << endl;
            cout << s - 1 << endl;
            return;
        }
    }
    int l = (s - n + 1);
    int r = n - 1;
    if(l > r + 1)
    {
        cout << "YES" << endl;
        for(int i = 1;i <= n - 1;i ++)
        {
            cout << 1 << " ";
        }
        cout << s - (n - 1) << endl;
        cout << r + 1 << endl;
    }else{
        cout << "NO" << endl;
    }
}
int main()
{
#ifdef LOCAL
    auto start_time = clock();
    cerr << setprecision(3) << fixed; // 在iomanip中
#endif
    SIS;
    slove();
#ifdef LOCAL
    auto end_time = clock();
    cerr << "Execution time: " << (end_time - start_time) * (int)1e3 / CLOCKS_PER_SEC << " ms\n";
#endif
}

Special Permutation

又是构造题,对于这个题目我们考虑利用奇偶性进行构造,因为两个奇数的差为2两个偶数的差也为2
那么我们呢考虑如果在两个能使1-n中间所有的奇数组成的序列和所有偶数的组成的序列连接在一起就好。

故我们对其进行分离 我们让所有的奇数降序排列
如果是10的话则有
奇数序列
9 7 5 3 1
此时我们有偶数序列 2 4 6 8 10
但是我们要保证交接出的差值>=2 且 <= 4
故我们固定中间的连接数为 4 2因为 4 和 1时终相差 3
2 和 6 时终相差 4都满足要求

但是如果给定的 n 小于 4 则无法满足要求!

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <cassert>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define lowbit(x) (x & -x)
using namespace std;
typedef long long ll;
const int MAX = 0x7ffffff;
int t;

void slove()
{
    int n;
    cin >> n;
    if(n < 4){
        cout << -1 << endl;
        return;
    }
    for(int i = n ;i >= 1;i --)
    {
        if(i & 1)cout << i << " ";
    }
    cout << 4 << " " << 2 << " ";
    for(int i = 6;i <= n ;i += 2)
    {
        cout << i << " ";
    }
    cout << endl;
}
int main()
{
#ifdef LOCAL
    auto start_time = clock();
    cerr << setprecision(3) << fixed; // 在iomanip中
#endif
    SIS;
    cin >> t;
    while(t--)
    {
        slove();
    }
#ifdef LOCAL
    auto end_time = clock();
    cerr << "Execution time: " << (end_time - start_time) * (int)1e3 / CLOCKS_PER_SEC << " ms\n";
#endif
}

Binary String Reconstruction

又是构造算法

如果 a > 0 至少有 a + 1 个连续的 0
此时 s 由 n - 1 个0组成
检查b 是否大于 2 大于二的话前面后面先各加一个
不大于2直接在最前面
如果 b == 0 但是 c >= 1 说明前面没有可以共享的1 需要自己在添加 1

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <cassert>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define lowbit(x) (x & -x)
using namespace std;
typedef long long ll;
const int MAX = 0x7ffffff;
int t;

void slove()
{
    int a , b , c;
    cin >> a >> b >> c;
    string s;
    if(a > 0)for(int i = 1;i <= a + 1;i ++)s += '0';
    if(a == 0 && b >= 1)s = '0';
    if(b >= 2)
    {
        s = '1' + s + '1';
        b -= 2;
        int x = 0;
        while(b--)
        {
            s += to_string(x);
            x = (x + 1) % 2;
        }
    }else if(b == 1)s = '1' + s;
    if(b == 0 && c >= 1)s = '1' + s;
    for(int i = 1;i <= c;i++)s = '1' + s;
    cout << s << endl;
}
int main()
{
#ifdef LOCAL
    auto start_time = clock();
    cerr << setprecision(3) << fixed; // 在iomanip中
#endif
    SIS;
    cin >> t;
    while(t--)
    {
        slove();
    }
#ifdef LOCAL
    auto end_time = clock();
    cerr << "Execution time: " << (end_time - start_time) * (int)1e3 / CLOCKS_PER_SEC << " ms\n";
#endif
}

Special Elements

暴力求出每一段的和,时间复杂度为\(O(n^{2})\),然后去判断这一段和在数组中出现次数统计后,将其置为0避免重复计数

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <cassert>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define lowbit(x) (x & -x)
using namespace std;
typedef long long ll;
const int MAX = 0x7ffffff;
int t;

void slove()
{
    int n;
    cin >> n;
    vector<int> a(n + 1) , cnt(n + 1);
    for(int i = 0;i < n ;i ++)
    {
        cin >> a[i];
        ++cnt[a[i]];
    }
    int ans = 0;
    for(int l = 0; l < n ; ++l)
    {
        int sum = 0;
        for(int r = l;r < n ; ++ r)
        {
            sum += a[r];
            if(l == r)continue;
            if(sum <= n)
            {
                ans += cnt[sum];
                cnt[sum] = 0;
            }
        }
    }
    cout << ans << endl;
}
int main()
{
#ifdef LOCAL
    auto start_time = clock();
    cerr << setprecision(3) << fixed; // 在iomanip中
#endif
    SIS;
    cin >> t;
    while(t--)
    {
        slove();
    }
#ifdef LOCAL
    auto end_time = clock();
    cerr << "Execution time: " << (end_time - start_time) * (int)1e3 / CLOCKS_PER_SEC << " ms\n";
#endif
}

LG-P1564 膜拜

大致是一个\(O(n^2)\)级别的时间复杂度根据最少我们猜想使用dp 或者 贪心
将问题转化为求最少能划分多少子区间使其满足,
区间内绝对值之和 <= m
dp[i] : 前 i 个人需要的最少机房数
为了简化计算我们可以对前缀和进行特殊处理

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>

using namespace std;

const int N = 2555;
int a[N] , n , m,sum[N] , f[N];
int main()
{

    cin >> n >> m;
    for(int i = 1;i <= n ;i ++)
    {
        cin >> a[i];
        if(a[i] == 1)sum[i] = sum[i-1] + 1;
        else sum[i] = sum[i-1] - 1;
    }
    memset(f , 0x7f ,sizeof f);
    f[1] = 1;f[0] = 0;
    for(int i = 1;i <= n ;i ++)
    {
        for(int j = 1;j < i ;j ++)
        {
            int t = abs(sum[i] - sum[j-1]);
            if(t <= m || t == i - j + 1)
            {
                f[i] = min(f[i], f[j-1] + 1);
            }
        }
    }
    cout << f[n] << endl;
    return 0;
}
posted @ 2020-05-20 20:39  _starsky  阅读(92)  评论(0编辑  收藏  举报