ACM-ICPC 2017 北京赛区现场赛 E,F,J

链接:HihoCoder 1631E

/* hihocoder 1631 : Cats and Fish
 * [题意]:给出n条鱼,m值猫,给出每个猫吃鱼的速度a[i]给出(吃的快的优先吃)。
 * 问x分钟后所剩的完整的鱼的数量,和不完整的鱼的数量。
 *
 * [分析]:由于吃鱼的速度不一样,将速度排序后,枚举1->x每个时间点,
 * 确认在当前状态下,每条鱼是否能够完整的吃完一条鱼和当前时间点是否开始吃下一条鱼。
 *
 *
 * [tricks]:
 * 注意速度为1的情况,直接完整的吃掉一条鱼。
 *
 * [时间复杂度]:x*m*t
 * */

#include <bits/stdc++.h>

#define  ll long long

using namespace std;

void scan() {
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif
}


int n, m, x;

const int maxn = 1e6 + 7;
int a[maxn], vis[maxn];

int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    scan();
    //cout<<999<<endl;
    while (cin >> n >> m >> x) {
        for (int i = 1; i <= m; i++) cin >> a[i], vis[i] = 0;
        sort(a + 1, a + 1 + m);
        int p = n, q = 0;
        for (int i = 1; i <= x; i++) {
            if (p == 0) break;
            for (int j = 1; j <= m; j++) {
                if (i % a[j] == 0) {
                    if (a[j] == 1 && p) p--;
                    if (vis[j] && q) vis[j] = 0, q--;
                } else {
                    if (!vis[j] && p) {
                        p--, q++, vis[j] = 1;
                    }
                }
                if (p == 0 && q == 0) break;
            }
            //cout<<"time: "<<i<<" || "<<p<<"***//  "<<q<<endl;
            if (p == 0 && q == 0) break;
        }
//        assert(p>=0),assert(q>=0);
        cout << p << " " << q << endl;
    }

    return 0;
}

链接:HihoCoder 1632F 

/* hihocoder 1632 : Secret Poems
 * [题意]:蛇形取数,回旋填数;
 *
 * [分析]:针对每一斜行, 奇数行往上,偶数行往下,注意角标就ok了,认真模拟一下。
 *
 * [tricks]:
 *
 *
 * [时间复杂度]:n*n
 * */

#include <bits/stdc++.h>

#define  ll long long

using namespace std;

void scan() {
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif
}


int n, m, x;

const int maxn = 1e3 + 7;

string ss[maxn], ans[maxn];

int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    scan();
    while (cin >> n) {
        string ret;
        for (int i = 0; i < n; i++) cin >> ss[i];
        for (int i = 0; i < 2 * n; i++) {
            if (i % 2) {
                for (int j = i; j >= 0; j--) {
                    if (i - j < n && j < n)
                        ret += ss[i - j][j];
                }
            } else {
                for (int j = 0; j <= i; j++) {
                    if (i - j < n && j < n)
                        ret += ss[i - j][j];
                }
            }
        }
        int l = 0, r = n - 1, up = 0, down = n - 1, cnt = 0, sz = ret.size();
        while (cnt < sz) {
            for (int i = l; i <= r; i++) ss[up][i] = ret[cnt++];
            for (int i = up + 1; i <= down; i++) ss[i][r] = ret[cnt++];
            for (int i = r - 1; i >= l; i--) ss[down][i] = ret[cnt++];
            for (int i = down - 1; i >= up + 1; i--) ss[i][l] = ret[cnt++];
            l++, r--, up++, down--;
        }
//        cout<<ret<<endl;
        for (int i = 0; i < n; i++) cout << ss[i] << endl;

    }

    return 0;
}

链接:HihoCoder 1636J 

/*HihoCoder 1636 : Pangu and Stones 区间DP
 *
 * 【题意】:给出n堆石子,每堆石子的数量为a[i],给出l,r,表示每进行一次合并,最少合并连续的l堆,最多合并连续r堆。
 * 问:最后石子合并为1堆时所需的花费。花费:合并的石子的数量。
 *
 *
 * 【分析】:很明显是个区间dp的经典问题,只不过是在这加了一个花费和堆的数量限制。
 * dp[st][ed][k]:区间[st,ed]分成k堆的花费。
 * 初始化:dp[st][st][1]=0;
 * 由于最后的k==1,因此在划分区间[st,ed]的时候,每次将其划分成1,k-1块。
 * 转移方程:dp[st][ed][k]=min(dp[st][ed][k],dp[st][mid][k-1]+dp[mid+1][ed][1]);
 *
 * 上述的转移方程是对于区间[st,ed]未加堆的限制下的之前的花费;
 *
 * 枚举堆的数量k-->[l-1,r-1],计算区间[st,ed]合并为1堆时的花费。
 *
 * 转移方程为:dp[st][ed][1] = min(dp[st][ed][1],dp[st][mid][k] + dp[mid + 1][ed][1] + sum[ed] - sum[st - 1]);
 *
 *
 * [tricks]:
 * 注意区间DP角标。
 *
 * [时间复杂度]:n^4
 *
 * */

#include <bits/stdc++.h>

#define  ll long long

using namespace std;

void scan() {
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif
}

const int maxn = 110;
const int INF = 0x3f3f3f3f;
int dp[maxn][maxn][maxn], a[maxn], sum[maxn];
int n, l, r;

int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    scan();
    while (cin >> n >> l >> r) {
        memset(dp, 0x3f, sizeof(dp));
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            sum[i] = sum[i - 1] + a[i];
            dp[i][i][1] = 0;;
        }
        for (int len = 2; len <= n; len++) {
            for (int st = 1; st + len - 1 <= n; st++) {
                int ed = st + len - 1;
                for (int k = 2; k <= min(len, r); k++) {
                    for (int mid = st + k - 2; mid < ed; mid++) {
                        dp[st][ed][k] = min(dp[st][ed][k], dp[st][mid][k - 1] + dp[mid + 1][ed][1]);
                    }
                }

                for (int k = l - 1; k <= r - 1; k++) {
                    for (int mid = st + k - 1; mid < ed; mid++) {
                        dp[st][ed][1] = min(dp[st][ed][1], dp[st][mid][k] + dp[mid + 1][ed][1] + sum[ed] - sum[st - 1]);
                    }
                }
            }
        }

        cout << (dp[1][n][1] == INF ? 0 : dp[1][n][1]) << endl;
    }

    return 0;
}

 感觉其它的题可以以后补吧。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值