920

又到了水题时间, 这次题目更水, AK的一大堆, 作为小菜鸡的我得了210分。。

我A掉的一道题, 时间复杂度为$O(n)$, 而n的范围 < 1000, 所以说太水了。 我们能够想到, 偷相同的钱所剩下的情况相同, 且偷钱时第一个口袋的钱一定会减少, 所以我们枚举第一个口袋所剩下的钱, 通过for循环来枚举出剩下的钱数, 求出总和记做sum2, 将原序列的sum1-sum2与ans进行比较, 取max就是最终的答案,  时间大概是$O(n * a[1])$, 大概是1e7, 已经能够过去了。 不过我又想到了一个$O(n)$的算法, 假设我们第一个口袋偷了x的钱, 由于和不变, 那么第二个口袋就加上x的钱, 第三的口袋就减去x的钱...不难看出, 当n为偶数时, 小偷是偷不了钱的, 当n为奇数时, 将标号为奇数的口袋的钱的数量取min, 最后减1输出即可

#include <bits/stdc++.h> 

using namespace std;

//typedef long long ll;
const int INF = 0x3f3f3f3f;
//const int MAXN = 5e5 + 100;
//const int MAXM = 3e3 + 10;
//const double eps = 1e-5;

template < typename T > inline void read(T &x) {
    x = 0; T ff = 1, ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') ff = -1;
        ch = getchar();
    }
    while(isdigit(ch)) {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar(); 
    }
    x *= ff;
}

template < typename T > inline void write(T x) {
    if(x == 0) {
        putchar('0');
        return ;
    }
    if(x < 0) putchar('-'), x = -x;
    static T tot = 0, ch[20];
    while(x) {
        ch[++tot] = x % 10 + '0';
        x /= 10;
    } 
    while(tot) putchar(ch[tot--]);
}
    
int n, x, ans = INF;

int main() {
    freopen("thief.in", "r", stdin);
    freopen("thief.out", "w", stdout);
    read(n);
    for(int i = 1; i <= n; ++i) {
        read(x);
        if(i & 1) ans = min(ans, x);
    }    
    --ans;
    if((n & 1) == 0) ans = 0;
    write(ans);
    return 0;
}
正解

做这道题时, 优秀的搜到了80分, 由于该数列严格单调递增, 且都为正整数, 所以最小的情况就是1, 2...,n, 我们枚举每一个i, 当a[i] > a[i - 1]时, 我们有两种选择, 一种是直接跳过这个点, 继续向下搜, 还有就是将a[i]赋成a[i - 1] + 1, 继续向下, 当a[i] $\le$ a[i - 1]时, 将a[i]赋成a[i - 1] + 1, 继续向下, 时间复杂度介于$O(n)$到$O(2 ^ n)$之间, 不过还是比较优秀的。 正解的话, 我们不妨设b[i] = a[i] - i;当b数组不下降时, a数组就是递增的, 所以我们只要求出b数组的单调不下降子序列len, n - len输出即可, 特别的,当b[i] < 0时, 该点一定会修改, 找子序列时跳过即可。

#include <bits/stdc++.h> 

using namespace std;

//typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 5e4 + 100;
//const int MAXM = 3e3 + 10;
//const double eps = 1e-5;

template < typename T > inline void read(T &x) {
    x = 0; T ff = 1, ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') ff = -1;
        ch = getchar();
    }
    while(isdigit(ch)) {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar(); 
    }
    x *= ff;
}

template < typename T > inline void write(T x) {
    if(x == 0) {
        putchar('0');
        return ;
    }
    if(x < 0) putchar('-'), x = -x;
    static T tot = 0, ch[20];
    while(x) {
        ch[++tot] = x % 10 + '0';
        x /= 10;
    } 
    while(tot) putchar(ch[tot--]);
}
    
int T, n, ans, a[MAXN], f[MAXN];
int flag = false;

inline void dfs(int x, int val) {
    if(val >= ans) return ;
    if(x == n + 1) {
        ans = min(ans, val);
        return ;
    }
    if(a[x] > a[x - 1]) {
        dfs(x + 1, val);
        if(a[x] - a[x - 1] > 1) {
            int u = a[x];
            a[x] = a[x - 1] + 1;
            dfs(x + 1, val + 1);
            a[x] = u;
        }
    }
    else {
        int u = a[x];
        a[x] = a[x - 1] + 1;
        dfs(x + 1, val + 1);
        a[x] = u;
    }
    return ;
}

int main() {
    freopen("noname.in", "r", stdin);
    freopen("noname.out", "w", stdout);
    read(T);
    while(T--) {
        read(n);
        flag = false;
        ans = INF;
        for(register int i = 1; i <= n; ++i) {
            read(a[i]); 
            if(a[i] <= a[i - 1]) flag = true;
        }
        if(!flag) {
            puts("0");
            continue;
        }
        dfs(1, 0);
        write(ans);
        puts("");
        
    } 
    return 0;
}
搜索
#include <bits/stdc++.h> 

using namespace std;

//typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 5e4 + 100;
//const int MAXM = 3e3 + 10;
//const double eps = 1e-5;

template < typename T > inline void read(T &x) {
    x = 0; T ff = 1, ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') ff = -1;
        ch = getchar();
    }
    while(isdigit(ch)) {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar(); 
    }
    x *= ff;
}

template < typename T > inline void write(T x) {
    if(x == 0) {
        putchar('0');
        return ;
    }
    if(x < 0) putchar('-'), x = -x;
    static T tot = 0, ch[20];
    while(x) {
        ch[++tot] = x % 10 + '0';
        x /= 10;
    } 
    while(tot) putchar(ch[tot--]);
}
    
int T, n, ans, len, a[MAXN], b[MAXN], f[MAXN];

int main() {
    freopen("noname.in", "r", stdin);
    freopen("noname.out", "w", stdout);
    read(T);
    while(T--) {
        read(n);
        for(register int i = 1; i <= n; ++i) {
            read(a[i]); 
            b[i] = a[i] - i;
        }
        memset(f, 0, sizeof(f));
        ans = 1;
        f[1] = b[1]; 
        for(register int i = 2; i <= n; ++i) {
            if(b[i] < 0) continue;
            if(b[i] >= f[ans]) f[++ans] = b[i];
               else f[upper_bound(f + 1, f + ans + 1, b[i]) - f] = b[i];
             
        }
        write(n - ans);
        puts(""); 
    } 
    return 0;
}
正解

emmmmm, 还是搜索吧, 枚举每个点由哪个员工去, 将答案去min, 时间复杂度为$O(3^n)$, 过掉了30分。 正解其实很好想, 是dp, 先Floyd求最短路, 设f[i][j][k]为完成前i个任务其余俩个人在j和k的最小花费, 则显然有

    f[i][j][k] = min(f[i][j][k], f[i - 1][j][k] + a[b[i - 1]][b[i]]);
    f[i][b[i - 1]][k] = min(f[i][b[i - 1]][k], f[i - 1][j][k] + a[j][b[i]]);
    f[i][b[i - 1]][j] = min(f[i][b[i - 1]][j], f[i - 1][j][k] + a[k][b[i]]);

我们可以设f[0][1][2] = f[0][2][1] = 0, b[0] = 3, 其余为INF, 目标状态是f[l][?][?]的最小值, $O(l * n ^ 2)$转移并取min就好了。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 5e2 + 100;
const int MAXM = 2e2 + 10;
const double eps = 1e-5;

template  < typename T > inline void read(T &x) {
    x = 0; T ff = 1, ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') ff = -1;
        ch = getchar();
    }
    while(isdigit(ch)) {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar(); 
    }
    x *= ff;
} 

template < typename T > inline void write(T x) {
    if(x == 0) {
        putchar('0');
        return ;
    }
    if(x < 0) putchar('-'), x = -x;
    static T tot = 0, ch[20];
    while(x) {
        ch[++tot] = x % 10 + '0';
        x /= 10;
    } 
    while(tot) putchar(ch[tot--]);
}

int T, n, l, ans, b[MAXN];
int a[MAXM][MAXM], f[MAXN][MAXM][MAXM];

inline void Floyd() {
    for(register int k = 1; k <= n; ++k) 
        for(register int i = 1; i <= n; ++i) 
            for(register int j = 1; j <= n; ++j) 
                a[i][j] = min(a[i][j], a[i][k] + a[k][j]);
}

int main() {
    freopen("service.in", "r", stdin);
    freopen("service.out", "w", stdout);
    read(T);
    while(T--) { 
        read(n); read(l); 
        for(register int i = 1; i <= n; ++i) {
            for(register int j = 1; j <= n; ++j) {
                read(a[i][j]);
            }
        }
        for(register int i = 1; i <= l; ++i) {
            read(b[i]);
        }
        Floyd();
        memset(f, 0x3f, sizeof(f));
        f[0][1][2] = 0;
        f[0][2][1] = 0;
        b[0] = 3;
        for(int i = 1; i <= l; ++i) {
            for(int j = 1; j <= n; ++j) {
                for(int k = 1; k <= n; ++k) {
                    int s = b[i - 1], t = b[i];
                    f[i][j][k] = min(f[i][j][k], f[i - 1][j][k] + a[s][t]);
                    f[i][s][k] = min(f[i][s][k], f[i - 1][j][k] + a[j][t]);
                    f[i][s][j] = min(f[i][s][j], f[i - 1][j][k] + a[k][t]);
                } 
            }
        }
        ans = INF;
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= n; ++j) {
                ans = min(ans, f[l][i][j]);
            } 
        }
        write(ans);
        puts("");
    }
    return 0;
} 
正解

猜你喜欢

转载自www.cnblogs.com/AK-ls/p/11568073.html
920
今日推荐