Codeforces Round 981 (Div. 3)(A-F)

感觉g是一个复杂的树上二分+dp,现在没有能力补

一场全是思维题

A Sakurako and Kosuke

 思路 

一个人往左边走一个奇数,一个人往右走一个奇数,很简单就可以知道,偶数是一个人,奇数也就是一人

代码

void solve() {
    ll x;
    cin >> x;
    if (x & 1) {
        cout << "Kosuke";
    }
    else {
        cout << "Sakurako";
    }
}

 B-- Sakurako and Water 

思路 

不难发现,如果我们进行一个矩形的对角线进行操作就对最大的进行操作就可以了,对矩形的所有的对角线进行遍历,最少的操作就是最小的数

 代码 

void solve() {
    ll n;
    cin >> n;
    vector<vector<ll>>arr(n + 2,vector<ll>(n + 2));
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> arr[i][j];
        }
    }
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
        ll j = 1;
        ll minn = 0;
        ll k = i;
        while (k <= n && j <= n) {
            minn = min(minn, arr[k][j]);
            k++;
            j++;
        }
        if (minn <= 0) {
            ans = ans - minn;
        }
    }
    for (int j = 2; j <= n; j++) {
        ll i = 1;
        ll k = j;
        ll minn = 0;
        while (i <= n && k <= n) {
            minn = min(minn, arr[i][k]);
            i++;
            k++;
        }
        if (minn <= 0) {
            ans = ans - minn;
        }
    }
    cout << ans;
}

C-Sakurako's Field Trip 

思路 

我们从中间或者两边开始移动就可以

证明:首先对于中间的2个或者3个数,移动不一定没有区别,例如 1 2 3 4 5,234是可以不用注意的,然后到了1 5,就是看看1是挨着2还是挨着5了,不需要注意1的左边和5的右边

代码 

void solve() {
    ll n;
    cin >> n;
    vector<ll>arr(n + 2);
    for (int i = 1; i <= n; i++) {
        cin >> arr[i];
    }
    ll l = n / 2;
    ll r = n / 2 + 1;
    if (n & 1) {
        r++;
    }
    l--;
    r++;
    while (l >= 1 && r <= n) {
        if (arr[l] == arr[l + 1] && arr[r] == arr[r - 1]) {
            swap(arr[l], arr[r]);
        }
        else {
            ll x = 0;
            if (arr[l] == arr[l + 1]) {
                x++;
            }
            if (arr[r] == arr[r - 1]) {
                x++;
            }
            ll y = 0;
            if (arr[l] == arr[r - 1]) {
                y++;
            }
            if (arr[r] == arr[l + 1]) {
                y++;
            }
            if (y <= x) {
                swap(arr[l], arr[r]);
            }
        }
        l--;
        r++;
    }
    ll ans = 0;
    for (int i = 1; i < n; i++) {
        if (arr[i] == arr[i + 1]) {
            ans++;
        }
    }
    cout << ans;
}

 D-- Kousuke's Assignment 

思路 

队友有用dp写的,但是暴力的复杂度是明显能过的,我这边写了个暴力的,我们从前往后遍历,统计前缀和,如果遇到相等的前缀和或者当前的前缀和为0,那么就是1个答案,然后清空map往下即可,有一点可能会产生疑惑,就是有没有可能前面的需要到后面产生最优解,实际上简单手搓就知道不会 

代码 

void solve() {
    ll n;
    cin >> n;
    vector<ll>arr(n + 2);
    for (int i = 1; i <= n; i++) {
        cin >> arr[i];
    }
    map<ll, ll>brr;
    ll sum = 0;
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
        if (arr[i] == 0) {
            ans++;
            brr.clear();
            sum = 0;
            continue;
        }
        sum = sum + arr[i];
        if (brr.count(sum) || sum == 0) {
            sum = 0;
            ans++;
            brr.clear();
            continue;
        }
        brr[sum]++;
    }
    cout << ans;
    
}

E-Sakurako, Kosuke, and the Permutation

思路   

通过题意不难判断,我们仅需要满足第二点即可,因为第一点包含在第二点里面,然后会发现,我们的区间最多形成的是二元环才可以,在受挫案例+结论证明下,对于一个n个点的环,只需要进行(n-1)/2就可以降低为最小为二元环的,然后并查集维护即可 赛时数组开小差点红温 

代码 

ll arr[2000021];
ll find(ll x) {
    if (arr[x] == x) {
        return x;
    }
    return arr[x] = find(arr[x]);
}
void join(ll x, ll y) {
    if (find(x) != find(y)) {
        arr[find(x)] = find(y);
    }
}
void solve() {
    ll n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        arr[i] = i;
    }
    vector<ll>brr(n + 2);
    for (int i = 1; i <= n; i++) {
        cin >> brr[i];
        if (brr[i] != i) {
            join(i, brr[i]);
        }
    }
    map<ll, ll>dp;
    for (int i = 1; i <= n; i++) {
        ll a = find(i);
        dp[a]++;
    }
    ll sum = 0;
    for (int i = 1; i <= n; i++) {
        
        if (dp[i] >= 3) {
            sum = sum + (dp[i] - 1) / 2;
        }
        
    }
    cout << sum;
    
    
}

 F-- Kosuke's Sloth

思路    

感觉像诈骗提,对于feibonaxie数列有一个性质,也就是第k项如果能整除以x那么第xi项均可以整除以x,那么我们找到第一项能整除k的下表然后乘以n就可以了  

代码  

ll dp[10002000];
void solve() {
    
    cin >> n >> k;
    if (k == 1) {
        cout << n % mod;
        return;
    }
    ll ans = 0;
    dp[1] = 1;
    dp[2] = 1;
    for (int i = 3;; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
        dp[i] = dp[i] % k;
        if (dp[i] == 0) {
            ans = i;
            break;
        }
    }
    n = n % mod;
    ans = ans % mod;
    ans = ans * n % mod;
    cout << ans;
    
 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值