Codeforces Round #806 (Div. 4)

Codeforces Round #806 (Div. 4)

https://codeforces.com/contest/1703

抱歉啊。。鸽了这么久。实在是最近太懒惰了唉

A. YES or YES?

(看到题目的时候DNA动了,差点唱出来)
直接按题意判断即可

#include <bits/stdc++.h>

using namespace std;

bool check (string s) {
    if (s[0] != 'Y' && s[0] != 'y') return false;
    if (s[1] != 'E' && s[1] != 'e') return false;
    if (s[2] != 'S' && s[2] != 's') return false;
    return true;
}

void solve () {
    string s;
    cin >> s;
   
    if (check (s))
        cout << "YES\n";
    else    cout << "NO\n";
}

int main () {
    int t;  cin >> t;
    while (t --)    solve ();
}

B. ICPC Balloons

模拟
第一次出现的字母+2,后续每出现一次都+1

#include <bits/stdc++.h>

using namespace std;

void solve () {
    int n, ans = 0;
    string s;
    cin >> n >> s;
    
    set<char>se;
    for (int i = 0; i < n; i ++) {
        if (se.count(s[i])) ans ++;
        else {
            ans += 2;
            se.insert (s[i]);
        }
    }
    cout << ans << endl;
}

int main () {
    int t;  cin >> t;
    while (t --)    solve ();
}

C. Cypher

(我读题不细心,后面的输入不是字符串,而是按字符输入)
给出操作后的结果以及操作过程,求开始的过程
全反即可 (U变D,D变U)
取模法则:( + 10)% 10,保证其在0-9的范围内

#include <bits/stdc++.h>

using namespace std;
const int N = 105;
int a[N];

void solve () {
    int n;  cin >> n;
    for (int i = 1; i <= n; i ++)   cin >> a[i];
    for (int i = 1; i <= n; i ++) {
        int x = a[i];
        int m;  cin >> m;
        //string s;   cin >> s;
        int cnt = 0;
        for (int j = 0; j < m; j ++) {
            char ch;    cin >> ch;
            if (ch == 'U')    cnt --;
            else    cnt ++;
        }
        cnt = (cnt+10)%10;
        //cnt %= 10;
        x += cnt, x = (x+10)%10;
        cout << x << ' ';
    }
    cout << endl;
}

int main () {
    int t;  cin >> t;
    while (t --)    solve ();
}
//给出操作后的结果以及操作过程,求开始的过程
//全反即可
//超出%10
//挨个输入的

D. Double Strings

每次给n个串,如果该串能由 其它两串 或 一串重复两次 拼接而成,则为输出1,否则输出0
一开始想的暴力维护set,O(n^2)TLE了。
突破点在于串的长度很小,所以可以从开头结尾向中间枚举(前后缀)

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5;
string s[N];
int n, sz;

void solve () {
    cin >> n;
    set <string> se;
    for (int i = 1; i <= n; i ++)   cin >> s[i], se.insert (s[i]);
    for (int i = 1; i <= n; i ++) {
        bool suc = false;
        for (int j = 1; j < s[i].size(); j ++) {
            string x = s[i].substr (0, j), y = s[i].substr (j); //前后缀 0到j-1, j到sz-1
            if (se.count (x) && se.count (y)) {
                suc = true;
                break;
            }
        }
        if (suc)    cout << 1;
        else    cout << 0;
    }
    cout << endl;
}

int main () {
    int t;  cin >> t;
    while (t --)    solve ();
}
//如果能被别的表示就是1
//n^2暴力 不行

//substr(st, len)
//因为长度小,所以可以从左右两端开始枚举

E. Mirror Grid

要求改变当前方阵,使得其顺时针翻转90°三次后的结果都重合。我的做法是多枚举几对翻转后重合的坐标,然后找规律,如图:

不难发现,一对坐标的规律就是:

(i,j)->(j,n-i+1)->(n-i+1,n-j+1)->(n-j+1,i)

注意for循环范围

#include <bits/stdc++.h>

using namespace std;
const int N = 105;
int n, g[N][N];
//string s[N];

void solve () {
    int ans = 0;
    cin >> n;
    for (int i = 1; i <= n; i ++) {
        string s;    cin >> s;
        for (int j = 0; j < n; j ++) {
            g[i][j+1] = s[j] - '0';
        }
    }
    

    //对角线
    for (int i = 1; i <= n/2;  i ++) {
        for (int j = 1; j <= (n+1)/2; j ++) {
            int a = g[i][j], b = g[j][n-i+1], c = g[n-i+1][n-j+1], d = g[n-j+1][i];
            int cnt = a + b + c + d;
            //if (cnt == 0 || cnt == 4)   continue;
            if (cnt == 1 || cnt == 3)   ans ++;
            if (cnt == 2)   ans += 2;
        }
    }

    cout << ans << endl;
}

int main () {
    int t;  cin >> t;
    while (t --)    solve ();
}
//四个行列都相等
//统计坐标关系
//找规律

F. Yet Another Problem About Pairs Satisfying an Inequality

找出满足\(a_i<i<a_j<j\)的(i,j)有多少对
直接把满足\(a_i<i\)\(a_i\)和i放进两个vector里,然后lower_bound二分查找即可

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N = 2e5 + 5;
int a[N], n;

void solve () {
    cin >> n;
    vector <int> v1, v2;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        if (a[i] < i) {
            v1.push_back (a[i]), v2.push_back (i);
        }
    }

    int ans = 0;
    n = v1.size();
    for (int i = 0; i < n; i ++) {
        ans += lower_bound (v2.begin(), v2.end(), v1[i]) - v2.begin();
    }
    cout << ans << endl;
}

signed main () {
    int t;  cin >> t;
    while (t --)    solve ();
}

//a[i]<i<[j]<j
//先把不满足a[i]<i的踢掉

G. Good Key, Bad Key

有好钥匙和坏钥匙。一把好钥匙会花费k; 坏钥匙使用过后,其后的所有物品价值都会变为原来的1/2。

做法一:贪心

好钥匙放前面一定是最优的,因为他不会使得物品减少,
随后就只需要求出最大可能放多少把即可(从后向前枚举)

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N = 1e5 + 5;
int a[N], sum[N], n, k;

void solve () {
    cin >> n >> k;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        sum[i] = sum[i-1] + a[i];
    }

    vector <int> s1;
    int ans = 0;
    for (int i = n; i >= 0; i --) {
        int cur = sum[i] - k * i;
        for (auto j : s1)   
            cur += j;
        ans = max (ans, cur);
        s1.push_back (a[i]);

        vector<int> s2;
        for (auto j : s1) {
            if (j > 1)
                s2.push_back (j / 2);
        }
        swap (s1, s2);
    }
    cout << ans << endl;
}

signed main () {
    int t;  cin >> t;
    while (t --)    solve ();
}

//11110000

做法二:dp

预处理a[i][j]: a[i][j] = a[i][0] >> j;
dp[i][j]表示到第i个箱子为止,一共使用了j次坏钥匙的产生的最大贡献:

  1. 当前宝箱用坏钥匙开 dp[i−1][j−1]+a[i][j]
  2. 当前宝箱用好钥匙开 dp[i−1][j]+a[i-1][j]−k
int n, m;
int a[N];
LL dp[N][35];//开第i个盒子用了j个bad钥匙能obtain的maximum
int pow2[N];

void solve()
{
	cin >> n >> m;
        for (int i = 1; i <= n; i++) {
	        cin >> a[i][0];
		dp[i][0] = 0;
		for (int j = 0; j <= min(i, 30); j++) {
			dp[i][j] = 0;
			a[i][j] = a[i][0] >> j;  // 预处理a[i][]
		}
	}

	LL ans = 0;
	for(int i = 1; i <= n; i ++ )
		for(int j = 0; j <= 30; j ++ ){
			if(j == 0) dp[i][j] = max(dp[i - 1][0] + a[i] - m, dp[i][j]);
			else{
				dp[i][j] = max({dp[i - 1][j - 1] + a[i] / pow2[j], dp[i - 1][j] + a[i] / pow2[j] - m});
			}
			ans = max(dp[i][j], ans);
		}
	printf("%lld\n",ans);
}

(感觉一个人多少有些自闭emm)

posted @ 2022-07-14 22:05  Sakana~  阅读(83)  评论(4编辑  收藏  举报