《5.9训练部分题解》

A:没写。

B:没写。

C:

m个块来考虑,假设当前为[1,m]位置都站满了。

现在我们要到[2,m + 1],如果a[1] > a[m + 1],跳过去之后a[m + 1]被站满。

如果a[1] < a[m + 1]那么跳过去没被站满,那么剩下的只能有[2,m]来填充。

那么综上所诉我们的答案就是所以m个块的和的最小值。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int N = 1e6 + 5;
const int M = 2000 + 5;
const LL Mod = 10007;
#define pi acos(-1)
#define INF 1e18
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO {
inline LL read() {
    LL x = 0, f = 1;
    char c = getchar();

    while (c < '0' || c > '9') {
        if (c == '-')
            f = -1;

        c = getchar();
    }

    while (c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }

    return x * f;
}
}
using namespace FASTIO;

LL a[N];
int main() {
    int n,m;n = read(),m = read();
    for(int i = 1;i < n;++i) a[i] = read();
    LL sum = 0;
    for(int i = 1;i <= m;++i) sum += a[i];
    LL ans = sum;
    for(int i = m + 1;i < n;++i) {
        sum -= a[i - m];
        sum += a[i];
        ans = min(ans,sum);
    }
    printf("%lld\n",ans);

    return 0;
}
View Code

D:

dp[i][j][k] - 到i修改了j次,第i个位置以k为结尾的最优解

枚举前一个位置是什么然后转移即可。

注意用滚动数组压缩空间。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int N = 1e5 + 5;
const int M = 350;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO {
inline LL read() {
    LL x = 0, f = 1;
    char c = getchar();

    while (c < '0' || c > '9') {
        if (c == '-')
            f = -1;

        c = getchar();
    }

    while (c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }

    return x * f;
}
}
using namespace FASTIO;

int dp[2][505][30];//dp[i][j][k] - 到i修改了j次,第i个位置以k为结尾的最优解
int main() {
    int n,t;
    n = read(),t = read();
    string s;cin >> s;
    memset(dp,0x3f3f3f,sizeof(dp));
    for(int k = 0;k < 26;++k) {
        int x = s[0] - 'a';
        if(x == k) {
            dp[1][0][x] = 1;
        }
        else {
            dp[1][1][k] = 1;
        }
    }
    for(int i = 2;i <= n;++i) {
        memset(dp[i % 2],0x3f3f3f,sizeof(dp[i % 2]));
        for(int j = 0;j <= t;++j) {
            if(j > t) break;
            int x = s[i - 1] - 'a';
            for(int k = 0;k < 26;++k) {
                if(x == k) {
                    dp[i % 2][j][k] = min(dp[i % 2][j][k],dp[(i + 1) % 2][j][k]);
                }
                else {
                    if(j > 0) {
                        dp[i % 2][j][k] = min(dp[i % 2][j][k],dp[(i + 1) % 2][j - 1][k]);
                    }
                    dp[i % 2][j][x] = min(dp[i % 2][j][x],dp[(i + 1) % 2][j][k] + 1);
                }
            }
        }
    }
    int ans = INF;
    for(int j = 0;j <= t;++j) {
        for(int k = 0;k < 26;++k) {
            ans = min(ans,dp[n % 2][j][k]);
        }
    }
    printf("%d\n",ans);
  //  system("pause");
    return 0;
}
View Code

E:

对于每个数只有三种操作,1-加入总和,2-变阶乘后加入总和,3-不加入总和。

那么复杂度就是3^n,显然这里会TLE,我们折半搜,先算前半部分,然后map存值。

再搜后半部分顺便统计答案,复杂度3^(n / 2)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL, int> pii;
const int N = 1e6 + 5;
const int M = 2000 + 5;
const LL Mod = 10007;
#define pi acos(-1)
#define INF 1e18
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO {
inline LL read() {
    LL x = 0, f = 1;
    char c = getchar();

    while (c < '0' || c > '9') {
        if (c == '-')
            f = -1;

        c = getchar();
    }

    while (c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }

    return x * f;
}
}
using namespace FASTIO;

int n,k;
LL s,ans = 0,f[20],a[30],dp[30][30];
map<LL,int> mp[30];
void init() {
    f[1] = 1;
    for(int i = 2;i <= 19;++i) f[i] = f[i - 1] * i;
}

void dfs(int x,int num,LL sum) {
    if(x == n / 2 + 1) {
     //   printf("%d %lld\n",k - num,sum);
        mp[k - num][sum]++;
        return ;
    }
    if(sum + a[x] <= s) dfs(x + 1,num,sum + a[x]);
    if(a[x] <= 19 && sum + f[a[x]] <= s && num > 0) dfs(x + 1,num - 1,sum + f[a[x]]);
    dfs(x + 1,num,sum + 0);
}
void dfs2(int x,int num,LL sum) {
    if(x == n + 1) {
        for(int i = 0;i <= num;++i) {
            ans += mp[i][s - sum];
        }
        return ;
    }
    if(sum + a[x] <= s) dfs2(x + 1,num,sum + a[x]);
    if(a[x] <= 19 && sum + f[a[x]] <= s && num > 0) dfs2(x + 1,num - 1,sum + f[a[x]]);
    dfs2(x + 1,num,sum + 0);
}
int main() {
    init();
    n = read(),k = read(),s = read();
    for(int i = 1;i <= n;++i) a[i] = read();
    dfs(1,k,0);
    dfs2(n / 2 + 1,k,0);
    printf("%lld\n",ans);
  //  system("pause");
    return 0;
}
/*
2 4 2
2 2
*/
View Code

F:

枚举第i位是什么数,然后dfs判断一下最大值。

假设我们现在能取到的最大值是x,然后我们现在枚举的数是a[i],那么我们下一个枚举的数的范围肯定是a[i] ~ x + 1。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL, int> pii;
const int N = 1e3 + 5;
const int M = 2000 + 5;
const LL Mod = 10007;
#define pi acos(-1)
#define INF 1e18
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO {
inline LL read() {
    LL x = 0, f = 1;
    char c = getchar();

    while (c < '0' || c > '9') {
        if (c == '-')
            f = -1;

        c = getchar();
    }

    while (c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }

    return x * f;
}
}
using namespace FASTIO;

int n,m,ans,a[15],dp[N],tmp[N];
void dfs(int x,int num,int sum,int limit) {
    dp[sum] = 1;
    if(x == limit) return ;
    for(int i = 0;i <= num;++i) {
        dfs(x + 1,num - i,sum + a[x] * i,limit);
    }
}
void solve(int x) {
    memset(dp,0,sizeof(dp));
    //for(int i = 1;i < x;++i) printf("%d%c",a[i],i == x - 1 ? '\n' : ' ');
    dfs(1,m,0,x);
    int L = a[x - 1] + 1,r;
    for(int i = 1;;++i) {
        if(dp[i] == 0) {
            r = i;
            break;
        }
    }
    if(r - 1 > ans) {
        for(int i = 1;i < x;++i) tmp[i] = a[i];
        ans = r - 1;
    }
    if(x == n + 1 || r < L) return ;
    for(int i = L;i <= r;++i) {
        a[x] = i;
        solve(x + 1);
    }
}
int main() {
    n = read(),m = read();
    a[1] = 1;
    ans = 1;
    solve(2);
    for(int i = 1;i <= n;++i) printf("%d%c",tmp[i],i == n ? '\n' : ' ');
    printf("%d\n",ans);
    return 0;
}
View Code

G:简单题

H:

首先,这里除了两个对角线之外出发都是组成环。并且这些环都可以看成从第一行的某个位置出发形成的环。

那么我们环的总个数就是n - 2 加上两个对角线2.一共只有n种不同性质的走法。

所以我们可以n^2枚举两个人的走法。注意在处理走法的时候同时处理一下重复的位置。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL, int> pii;
const int N = 1e5 + 5;
const int M = 2000 + 5;
const LL Mod = 10007;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO {
inline LL read() {
    LL x = 0, f = 1;
    char c = getchar();

    while (c < '0' || c > '9') {
        if (c == '-')
            f = -1;

        c = getchar();
    }

    while (c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }

    return x * f;
}
}
using namespace FASTIO;

int n,a[1005][1005],sum[1005],dir[1005][1005][5];
int lp[1005][1005];
bool vis[1005][1005];
int main() {
    n = read();
    for(int i = 1;i <= n;++i)
        for(int j = 1;j <= n;++j) a[i][j] = read();
    for(int i = 1;i <= n;++i) {
        int nowx = 1,nowy = i,cx = 1,cy = 1,id = 1;
        if(i == n) cx = 1,cy = -1,id = 2;
        memset(vis,0,sizeof(vis));
        while(vis[nowx][nowy] == 0) {
            sum[i] += a[nowx][nowy];
            vis[nowx][nowy] = 1;
            dir[nowx][nowy][id] = i;
            for(int j = 1;j <= 4;++j) {
                lp[i][dir[nowx][nowy][j]] += a[nowx][nowy];
                lp[dir[nowx][nowy][j]][i] += a[nowx][nowy];
            }
            if(nowx == n && nowy == n) break;
            if(nowx == n && nowy == 1) break;
            nowx += cx,nowy += cy;
            if(nowy == n) {
                cx = 1,cy = -1;
                id = 2;
            }
            if(nowx == n) {
                cx = -1,cy = -1;
                id = 3;
            }
            if(nowx == 1) {
                cx = 1,cy = 1;
                id = 1;
            }
            if(nowy == 1) {
                cx = -1,cy = 1;
                id = 4;
            }
        }
    }
    int ans = 0;
    //or(int i = 1;i <= n;++i) printf("%d\n",sum[i]);
    for(int i = 1;i <= n;++i) {
        for(int j = i + 1;j <= n;++j) {
            ans = max(ans,sum[i] + sum[j] - lp[i][j]);
        }
    }
    printf("%d\n",ans);
  //  system("pause");
    return 0;
}
View Code

I:

可搜索可转压。

我这里用了状压。

dp[i][j]表示i状态下j营养的数量。

转移就每次枚举一位没有的加入即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int N = 5e5 + 5;
const int M = 2000 + 5;
const LL Mod = 10007;
#define pi acos(-1)
#define INF 1e18 + 5
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO {
inline int read() {
    int x = 0, f = 1;
    char c = getchar();

    while (c < '0' || c > '9') {
        if (c == '-')
            f = -1;

        c = getchar();
    }

    while (c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }

    return x * f;
}
}
using namespace FASTIO;

int a[30],b[20][30],ans[20],p[20],n;
int dp[1 << 15][30];

bool check(int x) {
    for(int i = 1;i <= n;++i) if(dp[x][i] < a[i]) return false;
    return true;
}
bool solve(int len) {
    for(int i = 1;i <= len;++i) {
        if(p[i] == ans[i]) continue;
        if(p[i] < ans[i]) return true;
        else return false;
    }
}
int main() {
    n = read();
    for(int i = 1;i <= n;++i) a[i] = read();
    int m;m = read();
    for(int i = 0;i < m;++i) {
        for(int j = 1;j <= n;++j) b[i][j] = read();
    }
    for(int i = 0;i < (1 << m);++i) {
        for(int j = 0;j < m;++j) {
            int g = ((i >> j) & 1);
            if(g == 0) {
                int x = i | (1 << j);
                for(int k = 1;k <= n;++k) {
                    dp[x][k] = dp[i][k] + b[j][k];
                }
            }
        }
    }
    //for(int i = 0;i < (1 << m);++i)
        //for(int j = 1;j <= n;++j) printf("dp[%d][%d] is %d\n",i,j,dp[i][j]);
    int len = 1000;
    for(int i = 0;i < (1 << m);++i) {
        if(check(i)) {
            int x = i,ta = 0;
            for(int j = 1;j <= m;++j) {
                if(x % 2 != 0) p[++ta] = j;
                x /= 2;
            }
            if(ta < len) {
                len = ta;
                x = i;
                int f = 0;
                for(int j = 1;j <= m;++j) {
                    if(x % 2 != 0) ans[++f] = j;
                    x /= 2;
                }
            }
            else if(ta == len && solve(len)) {
                x = i;
                int f = 0;
                for(int j = 1;j <= m;++j) {
                    if(x % 2 != 0) ans[++f] = j;
                    x /= 2;
                }
            }
        }
    }
    printf("%d",len);
    for(int i = 1;i <= len;++i) printf(" %d",ans[i]);
    return 0;
}
/*
4
1250 200 300 400
5
100 200 300 400
900 150 389 399
200 300 200 300
50  50  50  50
500 120 150 300
*/
View Code

H:bfs即可。

hash一下数字的状态来节省空间。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int N = 5e5 + 5;
const int M = 2000 + 5;
const LL Mod = 10007;
#define pi acos(-1)
#define INF 1e18 + 5
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO {
inline int read() {
    int x = 0, f = 1;
    char c = getchar();

    while (c < '0' || c > '9') {
        if (c == '-')
            f = -1;

        c = getchar();
    }

    while (c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }

    return x * f;
}
}
using namespace FASTIO;

map<int,int> mp;
int st,cnt = 0,pos0,b[4][2] = {1,0,-1,0,0,1,0,-1},a[10];
struct Node{
    int x,step,pos;
};
int cal(int x) {
    if(x <= 3) return 1;
    else if(x <= 6) return 2;
    else return 3;
}
int cal2(int x) {
    if(x % 3 == 0) return 3;
    else return x % 3;
}
int cha(int x,int y) {
    int ma = 0;
    if(x == 1) ma += 0;
    else if(x == 2) ma += 3;
    else ma += 6;
    ma += y;
    return ma;
}
int bfs() {
    queue<Node> Q;
    Q.push(Node{st,0,pos0});
    while(!Q.empty()) {
        Node q = Q.front();
        Q.pop();
        if(q.x == 123804765) return q.step;
        int nowx = cal(q.pos),nowy = cal2(q.pos);
        int ta = q.x;
        //printf("ta is %d pos is %d\n",ta,q.pos);
        for(int i = 9;i >= 1;--i) a[i] = ta % 10,ta /= 10;
        for(int i = 0;i < 4;++i) {
            int px = nowx + b[i][0];
            int py = nowy + b[i][1];
            if(px >= 1 && px <= 3 && py >= 1 && py <= 3) {
                int ma = cha(px,py);
                swap(a[q.pos],a[ma]);
                int tmp = 0;
                for(int i = 1;i <= 9;++i) tmp = tmp * 10 + a[i];
                if(mp[tmp] == 0) {
                    mp[tmp] = ++cnt;
                    Q.push(Node{tmp,q.step + 1,ma});
                }
                swap(a[q.pos],a[ma]);
            }
        }
    }

}


int main() {
    st = read();
    mp[st] = ++cnt;
    int i = 9,ff = st;
    while(ff) {
        if(ff % 10 == 0) {
            pos0 = i;
            break;
        }
        ff /= 10;
        i--;
    }
    printf("%d\n",bfs());
    return 0;
}
View Code

 

posted @ 2021-05-11 09:01  levill  阅读(204)  评论(0编辑  收藏  举报