Codeforces Round #717 (Div. 2) A - C

OB局,最近莽数据库作业没什么时间,大晚上也挺困的。

A - Tit for Tat

概括来讲,对于\(n\)个数,最多进行\(k\)次操作,每次操作可以使一个数-1,一个数+1,最终得到的序列字典序最小。

每次操作就对第一个非0的数-1,对最后一个数+1。

如果第一个非0的数就是最后一个数,就可以停止操作了。

/* Author: EndlessK
 * Time: 2021-04-22 12:37:38
**/
#include<bits/stdc++.h>
#define maxn 100010
#define pb push_back
#define ll long long
#define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
int a[110];
int main()
{
    fast;
    int t;
    cin>>t;
    while(t--)
    {
        int n,k;
        cin>>n>>k;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        int temp=1;
        for(int i=1;i<=k;i++)
        {
            while(a[temp]==0 && temp<n) temp++;
            if(temp==n) break;
            a[temp]--;
            a[n]++;
        }
        for(int i=1;i<=n;i++)
        {
            cout<<a[i]<<' ';
        }
        cout<<'\n';
    }
    return 0;
}
View Code

 

B - AGAGA XOOORRR

当时口糊一个算法,随便写了一发让别人交了,A了,第二天起来自己交Wrong answer on test 18,效果拉满。

题目概括起来讲就是将一个序列分成若干段,使得这几段的异或和相等。

两个相等的数异或和为0。

先求序列所有数字的异或和,如果为0,那么整个序列必然可以分成两段使得这两段的异或和相等。

如果不为0,那么留下的这个数字就是每段异或和的值\(sum\)。那么我就看前面异或和为0的部分能不能分成两段异或和为\(sum\)的序列。

当晚口糊的居然是看每一小段异或和为0的部分能不能分成两段异或和为\(sum\)的序列。早晨起来发现加了17和18两组,正好叉掉了。

 1 #include <bits/stdc++.h>
 2 #define maxn 100010
 3 #define pb push_back
 4 #define ll long long
 5 #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
 6 const ll mod = 1e9 + 7;
 7 using namespace std;
 8 int n;
 9 int a[2020];
10 int sum[2020] = {0};
11 vector<int> v;
12 bool check(int l, int r)
13 {
14     int temp = 0;
15     for (int i = l; i <= r; i++)
16     {
17         temp = temp ^ a[i];
18         if (temp == sum[n])
19             return 1;
20     }
21     return 0;
22 }
23 int main()
24 {
25     int t;
26     cin >> t;
27     while (t--)
28     {
29         v.clear();
30         cin >> n;
31         for (int i = 1; i <= n; i++)
32         {
33             cin >> a[i];
34             sum[i] = sum[i - 1] ^ a[i];
35             if (sum[i] == 0)
36                 v.pb(i);
37         }
38         if (sum[n] == 0)
39             cout << "YES\n";
40         else
41         {
42             if (v.size() == 0)
43             {
44                 cout << "NO\n";
45                 continue;
46             }
47             int flag = 1;
48             int tmp = 1;
49             if(check(1,v[v.size()-1])) cout<<"YES\n";
50             else cout<<"NO\n";
51         }
52     }
53 }
View Code

 

C - Baby Ehab Partitions Again

隔壁的暴力居然过了,虽然我到现在还在怀疑是不是对的。

概括起来就是,判断能不能将所有数字分成两组使得两组和相等,不能则为0,若能,问最少删除多少个数字使得无法分成符合条件的两组。

1.和为奇数,结果必为0。

2.和为偶数,若数字中有奇数,删除奇数。

3.对于上一条,若全为偶数,则不断除2,直至奇数出现,而那个奇数就是我们需要删除的数字。

对于所有可能和的求解像极了蓝桥的砝码称重()

终于想到用背包写了,谢天谢地,不然我还在那写set。

/* Author: EndlessK
 * Time: 2021-04-22 12:37:38
**/
#include<bits/stdc++.h>
#define maxn 100010
#define pb push_back
#define ll long long
#define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
int a[120];
int sum=0;
int main()
{
    fast;
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        sum+=a[i];
    }
    if(sum%2)
    {
        cout<<"0\n";
        return 0;
    }
    ll dp[sum/2+1][n+1];
    memset(dp,0,sizeof(dp));
    for(int i=0;i<=n;i++)
    {
        dp[0][i]=1;
    }
    for(int i=1;i<=sum/2;i++)
    {
        for(int j=1;j<=n;j++)
        {
            dp[i][j]=dp[i][j-1];
            if(i>=a[j-1])
            dp[i][j]=max(dp[i-a[j-1]][j-1],dp[i][j]);
        }
    }
    if(dp[sum/2][n]==0)
    {
        cout<<"0\n";
        return 0;
    }
    for(int i=1;i<=16;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(a[j]%2)
            {
                cout<<"1\n"<<j<<'\n';
                return 0;
            }
            else a[j]/=2;
        }
    }
    return 0;
}
View Code

 

之后有空补一下剩下两道题。

posted @ 2021-04-22 15:21  cyanine_告别  阅读(138)  评论(0编辑  收藏  举报