220707个人赛(题目来源Codeforces Round #674 (Div. 3) )

题目来源

A

签到

#include<bits/stdc++.h>

using namespace std;

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

void solve(){
   int n = read() , p = read();
   if( n <= 2 )
       cout << "1\n";
   else {
       n -= 2;
       cout << n / p + ( n % p > 0 ) + 1 << "\n";
   }
    return;
}

int32_t main() {
    int t = read();
    while( t -- )
        solve();
    return 0;
}

B

只要有一种是(1,2),(2,2)相等的,就一定可以,反之不行

#include<bits/stdc++.h>

using namespace std;

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

int n , m , flag;

void solve(){
    n = read() , m = read() , flag = 0;
    for( int i = 1 , a , b , c , d ; i <= n ; i ++ ){
        cin >> a >> b >> c >> d;
        if( b == c ) flag = 1;
    }
    if( m % 2 ) flag = 0;
    cout << ( flag ? "YES\n" : "NO\n");
}

int32_t main() {
    int t = read();
    while( t -- )
        solve();
    return 0;
}

C

贪心题目,先自增到$\left \lfloor \sqrt n \right \rfloor $,然后一直分裂就好,证明可以用求导

#include<bits/stdc++.h>
#define int long long
using namespace std;

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

int n , m , ans ;
vector< int > cnt , res;

void dfs( int mx , int t , int sum ){
    if( t >= ans ) return;
    if( sum >= n ) {
        ans = t;
        res = cnt;
        return;
    }
    cnt.push_back(mx);
    dfs( mx , t + 1 , sum + mx );
    cnt.pop_back();
    cnt.pop_back() , cnt.push_back(mx+1);
    dfs( mx +1 , t + 1 , sum + 1 );
    cnt.pop_back() , cnt.push_back(mx);
    return;
}

void solve(){
    n = read() , m = sqrt(n);
    if( n == 1 ){
        printf("0\n");
        return;
    }
    cout << ( m - 1 ) + ( n / m + (n % m > 0 ) - 1 ) << "\n";
}

int32_t main() {
    int t = read();
    while( t -- )
        solve();
    return 0;
}

D

字段和为 0,说明在前缀和中他们的值相同,然后我们把所有前缀和相等的位置连一条边,问最少切多少次可以把所有的边切断,这样这道题就转化成了luogu P1803 凌乱的yyy / 线段覆盖

然后发现如果是1,2,3这个三个点两年连边,发现1,3连边是没有必要的,只要1,22,3的边断开他也一定会断开,所以连边规则就变成了相等且相邻的点之间连边

这样的话,我们就不用想P1803那么做了,只要用 set 维护当前点的集合,如果当前点在集合中存在就要切一刀,同时集合中所有点先后的连边也都会被断开,所以可以直接把集合清空。

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N = 200000 + 5;
int n , cnt;
set< int > st;

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

int32_t main() {
    n = read();
    st.insert(0);
    for( int i = 1 , sum = 0 , x; i <= n ; i ++ )
    {
        x = read() , sum += x;
        if( st.count(sum) )
            cnt ++ , st.clear() , sum = x ,  st.insert(0);
        st.insert(sum);
    }
    cout << cnt << endl;
    return 0;
}

E

先说赢的最多的情况,如果B出剪刀A就要出石头直到一方的石头或剪刀用完,然后重复这个过程记录次数就好

在说赢得少的情况,如果B出剪刀A就要出布,直到一方完全出完,然后如果是B的剪刀先出完,那么A要继续在B出布的时候出布,直到一方出完,如果此时还有剩余的布,就只能在B出石头的时候出,这是剩下的布的数量才是必须赢且赢得最少的次数。

但是上述两种情况还要考虑剪刀石头布的顺序问题,因为数据很少直接枚举出所有的顺序就好

#include<bits/stdc++.h>

using namespace std;

int n , a[5] , b[5] , c[5] , d[5] , e[5] , ans = 1e9 + 7, res ,ans1 , res1;

int32_t main() {
    cin >> n;
    for( int i = 0 ; i < 3 ; i ++ ) cin >> a[i];
    for( int i = 0 ; i < 3 ; i ++ ) cin >> b[i];
    for( int i = 0 ; i < 3 ; i ++ )
        c[i] = a[i] , d[i] = b[i] , e[i] = i;

    do{
        ans1 = res1 = 0;
        for( int i = 0 ; i < 3 ; i ++ )
            a[i] = c[i] , b[i] = d[i];
        for( int i = 0 , x , y ; i < 3 ; i ++ )
            x = e[i] , y = ( x + 1 ) % 3 , res1 += min( a[x] , b[y] );
        for( int i = 0 , x , y ; i < 3 ; i ++ )
        {
            x = e[i] , y = ( x + 2 ) % 3 ;
            if( a[x] >= b[y] ) a[x] -= b[y] , b[y] = 0;
            else b[y] -= a[x] , a[x] = 0;
            if( a[x] >= b[x] ) a[x] -= b[x] , b[x] = 0;
            else b[x] -= a[x] , a[x] = 0;
        }
        for( int i = 0 ; i < 3 ; i ++ ) ans1 += a[i];
        ans = min( ans , ans1 ) , res = max( res , res1 );
    }while( next_permutation(e,e+3) );
    
    cout << ans << " " << res << endl;
    return 0;
}

F

没出现一个?就会导致序列的数量乘3,这道题我的做法是dp,先说一下状态

f[i][0]表示前i位有多少个序列空序列

f[i][1]表示前i位有多少个a

f[i][2]表示前i位有多少个ab

f[i][3]便是前i位有多少个abc

显然答案是f[n][3]

然后考虑状态的转移

先说s[i] == af[i][1]就是之前a的个数加上之前空序列个数

s[i] == bf[i][2]就是之前的ab的个数加上a的个数 ,s[i]==c时类似

但是a[i]==?,情况比较复杂,每一种序列的倍数都会乘 3,加上比这种序列短一个的序列和这个?

组成的序列

然后推一下状态转移方程就好

然后发现数组可以滚动数组优化一下空间

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int mod =1e9+7;
string s;
int f[5];

int32_t main() {
    f[0] = 1;
    cin >> s >> s;
    for( auto c : s ){
        if( c == '?' ){
            for( int i = 3 ; i >= 1; i -- )
                f[i] = ( f[i] * 3 + f[i-1] ) % mod;
            f[0] = f[0] * 3 % mod;
        }
        else {
            int i = c - 'a' + 1 ;
            f[i] = ( f[i] + f[i-1] ) % mod;
        }
    }
    cout << f[3];
    return 0;
}
posted @ 2022-07-09 15:31  PHarr  阅读(28)  评论(0编辑  收藏  举报