跳转至

Codeforces Round 1009 (Div. 3)

比赛时间: 2025-03-11

比赛链接: https://codeforces.com/contest/2074

本来 carrot 预测的是差不多加到我差几分上绿。但是一早上醒来发现我前面好多人被 hack 了,中午的时候我排名升了 50名。然后晚上重测完之后,排名有上升了一百多,总共升了150多... 太多人 FST 了吧。

于是我幸运的再次回到了蓝名。

赛时其实 D 题很久都没思路,然后我以为我 div. 3 会和 div. 2 一样的题数,有点难受了。于是没抱很大希望去看一下 E 题,然后以为就直接模拟就行,于是随便交一发, TLE ,然后改了又 TLE ,之后想着看能不能混过去用了 rand( ) ,毫无疑问过了,而且这还真就是正解。。。

最后看到 D 题的小提示,也成功 AC 了。就是慢了点。不过尽管如此,这场比赛是我 CF 打过的 rank 最好的一场比赛,rated里的 550 名。继续加油吧。而且写完这篇博客,最近的基本就补得差不多了。。。还有AtCoder的,,,感觉真是写不完的博客,补不完的题目啊。

前三题比较基础就不详细解释了。

A

void ChatGptDeepSeek()
{
    array<int, 4>a;
    for(int i=0;i<4;i++)
        cin>>a[i],a[i]=abs(a[i]);
    sort(a.begin(),a.end());
    if(a[0]==a[3])
        cout<<"YES\n";
    else
        cout<<"NO\n";
}

B

void ChatGptDeepSeek()
{
    int n;
    cin>>n;
    int sum=0;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        sum+=x;
    }
    cout<<sum-(n-1)<<'\n';
}

C

void ChatGptDeepSeek()
{
    int x;
    cin >> x;
    // x+y>=x^y
    // 111
    // 101
    // 010
    for (int i = 30; i >= 1; i--) {
        if (x >> i & 1) {
            int y = (1 << i) - 1;
            int z = x ^ y;
            if ((x != y) && z < x + y && x + z > y && y + z > x) {
                cout << y << '\n';
                return;
            }
        }
    } // 11
    // 01
    // 10
    cout << "-1\n";
}

D

本以为这场 div. 3 将会耻辱地只写出 3 题,这个 D 题给我看傻了。

最后写完 E 题回来看,注意了一句之前没怎么注意的话。。。

∗Is this information really useful? Don't ask me; I don't really know.

因为感觉这个有点意思,所以就多看了两眼,发现原来这个这么有用。。。

\(\sum r=m\) 意味着所有的横坐标,最多只会有 \(2m\) 个,所以直接对于每一个横坐标枚举即可。

void ChatGptDeepSeek()
{
    int n, m;
    cin >> n >> m;
    vector<int> l(m * 2 + 1), x(n + 1), r(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> x[i];
    for (int i = 1; i <= n; i++)
        cin >> r[i];
    set<pair<int, int>> st;
    auto Insert = [&](int X, int Y) {
        auto it = st.lower_bound({ X, 0 });
        if (it == st.end() || it->first != X) {
            st.insert({ X, Y });
        } else {
            if (Y > it->second) {
                st.erase(it);
                st.insert({ X, Y });
            }
        }
    };
    for (int i = 1; i <= n; i++) {
        for (int j = x[i] - r[i]; j <= x[i] + r[i]; j++) {
            //(j-x[i])*(j-x[i])+y*y<=r*r
            // 可以知道y的范围
            int y = sqrt(1LL * r[i] * r[i] - 1LL * (j - x[i]) * (j - x[i]));
            Insert(j, y);
        }
    }
    long long sum = 0;
    for (auto [X, Y] : st) {
        sum += 2 * Y + 1;
    }
    cout << sum << '\n';
}

E

如果不限制次数,肯定就是一直问 \((1,2,x)\) 这样,但是有可能最多需要问 \(n\) 次。

由于这题不允许 \(hack\) ,所以尝试用随机数来混过去。。。

但这就是正解,每次在中心有点后,随机两个顶点和这个点组成新的三角形。这样每次点的数量平均会减少 \(\frac{2}{3}\) ,所以其实非常非常大的概率是询问次数很小就行了。

也是我第一次通过跟 rand() 有关的题目了。

int ask(int a, int b, int c)
{
    cout << "? " << a << " " << b << " " << c << endl;
    int x;
    cin >> x;
    return x;
}
void ChatGptDeepSeek()
{
    int n;
    cin >> n;
    int x = 1, y = 2, z = 3;
    for (int i = 1; i <= 75; i++) {
        int X=ask(x,y,z);
        if(!X){
            cout<<"! "<<x<<" "<<y<<" "<<z<<endl;
            return;
        }
        int Y=rand();
        if(Y%3==0) x=X;
        else if(Y%3==1) y=X;
        else z=X;
    }
}

F

本来连题目都没看懂来着,,感觉看着有一点难受。

看了两种思路。

楜桃林的 Codeforces 题解

先用小的正方形来填充,若是可以用更大的正方形,那么一定可以把这个正方形替换成4个小一号的正方形。

所以可以先全部用小的正方形,若是能用大的正方形,则用的正方形的数量可以减少3倍的大正方形的数量。

void ChatGptDeepSeek()
{
    int l1, r1, l2, r2;
    cin >> l1 >> r1 >> l2 >> r2;
    long long ans = 1ll * (r1 - l1) * (r2 - l2);
    for (int i = 1; i < 30; i++)
    {
        int s = 1 << i;
        int L1 = (l1 + s - 1) / s * s;
        int L2 = (l2 + s - 1) / s * s;
        int R1 = r1 / s * s;
        int R2 = r2 / s * s;
        if (L1 >= R1 || L2 >= R2)
            continue;
        ans -= 3LL * (R1 - L1) / s * (R2 - L2) / s;
    }
    cout << ans << '\n';
}

ksun48的思路

比如 \(k=1\) 时,若 \(l1 , r1,l2,r2\) 为奇数,则必须使用 \(k=0\) 的正方形来填充。我们可以先把这一部分加上,之后 \(l1,r1,l2,r2\) 一定会全是偶数了,并且再也不会使用 \(k=1\) 的三角形了。

于是我们可以把这四个数字除以二,于是可以一直重复之前的操作了。

void solve(){
    ll lx, rx, ly, ry;
    cin >> lx >> rx >> ly >> ry;
    ll ans = 0;
    while(true){
        if(lx == rx || ly == ry) break;
        if(lx & 1){
            ans += (ry - ly);
            lx += 1;
        }
        if(rx & 1){
            ans += (ry - ly);
            rx -= 1;
        }
        if(ly & 1){
            ans += (rx - lx);
            ly += 1;
        }
        if(ry & 1){
            ans += (rx - lx);
            ry -= 1;
        }
        lx /= 2; rx /= 2; ly /= 2; ry /= 2;
    }
    cout << ans << '\n';
}

G

tag: 区间DP

好好好,这么会区间DP。好像还真是比较基础的区间DP,然而我是看题解做的。虽然看起来这个是一个环,但是其实并不需要特别处理。

\(dp_{i,j}\) 表示区间 \([i,j]\) 的最大答案。那么 \(dp_{l,r}=max(dp_{l,r},dp_{l+1,m-1}+dp_{m+1,r-1}+a_la_ma_r)\)

但是也可能中间已经有更好的方案,所以再加一个 \(dp_{l,m}+dp_{m+1,r}\)

void ChatGptDeepSeek()
{
    int n;
    cin >> n;
    vector<vector<long long>> dp(n + 1, vector<long long>(n + 1));
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int len = 3; len <= n; len++)
    {
        for (int l = 1; l + len - 1 <= n; l++)
        {
            int r = l + len - 1;
            for (int m = l + 1; m < r; m++)
                dp[l][r] = max(dp[l][r], dp[l + 1][m - 1] + dp[m + 1][r - 1] + a[l] * a[m] * a[r]);

            for (int m = l; m + 1 <= r; m++)
                dp[l][r] = max(dp[l][r], dp[l][m] + dp[m + 1][r]);
        }
    }
    cout << dp[1][n] << '\n';
}

End

2025-03-25

时隔两周,终于把这场Div. 3补完了。并且只有FG需要补且都是今天写的。。。且都看了题解。

但是无论如何终于把这一套给结束了,需要补的题总是少了一点的。今晚又有一场Div. 3,而且这次我可以 unrated 了,爽了。

好像我总共都没有 unrated 打过几场比赛。。因为比赛少且掉分比较快。。。慢慢来吧,虽然要补的题也会越来越多。但是无论如何我的写题量也会越来越多,实力也会提高的。

提升水平才是真正的目的。