Educational Codeforces Round 145 (Rated for Div. 2) 感想



感想

刚开始遇到了一阵诡异的网络问题,还有个挺无法理解的东西(下面的B题),很微妙。

A. Garland

1.题目内容

题目地址

2.个人思路

比较直白,四个相同就是-1,三个就是6次,一和二就是四次。

3.代码

ll t, n, m, p = 1000000007, k;
ll dp[300005][2];
map<char, int> ci;
string s;
 
int main() {
    cin >> t;
    while (t--) {
        cin >> s;
        ci.clear();
        for (int i = 0; i <= s.size(); i++) {
            ci[s[i]]++;
        }
        int ma = 0;
        for (auto x : ci) {
            ma = max(ma, x.second);
        }
        if (ma == 1) {
            cout << "4\n";
        }
        if (ma == 2) {
            cout << "4\n";
        }
        if (ma == 3) {
            cout << "6\n";
        }
        if (ma == 4) {
            cout << "-1\n";
        }
    }
    return 0;
}

B. Points on Plane

1.题目内容

题目地址

2.个人思路

可以画个图看一下,代价为0的只有一个,为1的有4个,为2的有8个…以此类推。然后任意两个点距离不能小于等于1,最佳情况一定就是每隔 \sqrt (2) 个距离去取点,然后就会发现实际上就是只能取代价差为2的点,也就是
0 2 4 …
1 3 5 …
这个规律取点。
然后发现这些求和正好是最大数字+1的平方,接下来只要对输入的n开方找数就可以了。
这个题我最早写的 != ,结果过不去,我琢磨了半天改成 < ,过了,也许跟自带的sqrt运算有关系吧,很迷惑。

3.代码

ll t, n, m, p = 1000000007, k;
ll dp[300005][2];
map<char, int> ci;
string s;
 
int main() {
    cin >> t;
    while (t--) {
        cin >> n;
        ll x = sqrt(n);
        if (x * x < n) {
            cout << x << "\n";
        }
        else {
            cout << x - 1 << "\n";
        }
    }
    return 0;
}

C. Sum on Subarrays

1.题目内容

题目地址

2.个人思路

思路其实很灵活的一个题,我看我周围的代码写成什么样的都有。
我个人的思路是左侧为正数,右侧为负数,直接为-1000,正数的子数组和肯定是正数,假设有x个正数
k的范围应该是(x)(x - 1) / 2 ~ (x)(x - 1) / 2 + x + 1
如果是不止(x)(x - 1) / 2的情况,就需要将第一个负数变小,小到与前面(k-(x)(x - 1) / 2)个子数组求和是正数即可,我这里设置成了正数是2,负数是-1000
,需要变化的负数是 -1 - (x+1-k+(x)(x - 1) / 2) * 2;

3.代码

ll t, n, m, p = 1000000007, k;
ll dp[300005][2];
map<char, int> ci;
string s;
 
int main() {
    cin >> t;
    while (t--) {
        cin >> n >> k;
        vector<int> ans;
        for (int i = 0; i < n; i++) {
            ans.push_back(-1000);
        }
        int now = 0;
        for (int i = 0; i < n; i++) {
            now += (i + 1);
            if (now <= k) {
                ans[i] = 2;
            }
            if (now < k && now + i + 2 > k) {
                ans[i + 1] = -1 - (i + 1 - k + now) * 2;
            }
        }
        for (int i = 0; i < ans.size(); i++) {
            cout << ans[i] << " ";
        }
        cout << "\n";
    }
    return 0;
}

D. Binary String Sorting

1.题目内容

题目地址

2.个人思路

其实就是dp,假设dp[i]是1~i有序情况下的最小消耗,cnt[i]为当前最小消耗下的1的数量,pos[i]是在s中到i时的1的总个数,此时就是有三种可能的方案。
交换代价以下称为c1,删除代价称为c2.
如果当前位置是0并且有大于0个1

  1. 把出现过的的1都删除掉,代价就是pos[i] * c2,cnt清空。
  2. 把这个0删除掉,代价就是dp[i - 1] + c2,cnt保持不变。
  3. 把0移动到1之前,代价是dp[i - 1] + cnt[i - 1] * c1,cnt保持不变。

如果当前位置是1,dp[i] = dp[i - 1],cnt[i] = cnt[i-1] + 1。
三个取最小即可。
如果出现相等(大概不会有)的情况,优先选择清空。
最后输出dp[n]即可。

3.代码

ll t, n, m, p = 1000000007, k;
ll c1 = 1e12, c2 = 1e12 + 1;
ll dp[300005], cnt[300005], pos[300005];
string s;
 
int main() {
    cin >> t;
    while (t--) {
        cin >> s;
        for (int i = 0; i < s.size(); i++) {
            cnt[i] = 0;
            dp[i] = 1e18;
            pos[i] = 0;
        }
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == '1') pos[i]++;
            if (i > 0) pos[i] += pos[i - 1];
        }
        dp[0] = 0;
        for (int i = 0; i < s.size(); i++) {
            if (i > 0 && s[i] == '0') {
                if (cnt[i - 1] > 0) {
                    ll xx = pos[i] * c2;
                    ll yy = dp[i - 1] + cnt[i - 1] * c1;
                    ll zz = dp[i - 1] + c2;
                    if (xx <= yy && xx <= zz) {
                        dp[i] = xx;
                        cnt[i] = 0;
                    }
                    else if(yy < zz && yy < xx) {
                        dp[i] = yy;
                        cnt[i] = cnt[i - 1];
                    }
                    else {
                        dp[i] = zz;
                        cnt[i] = cnt[i - 1];
                    }
                }
                else if (cnt[i] == 0) {
                    dp[i] = dp[i - 1];
                }
            }
            else {
                if (i == 0 && s[i] == '1') cnt[i] = 1;
                else if (i > 0) {
                    cnt[i] = cnt[i - 1] + 1;
                    dp[i] = dp[i - 1];
                }
            }
        }
        cout << dp[s.size() - 1] << "\n";
    }
    return 0;
}

总结

后面写到E发现就过了70个人,直接睡觉去了(电脑没电了),属于是我不配的领域了,对不起。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值