Codeforces Round #726 (Div. 2)(A B C D E F)

A-Arithmetic Array

题意:给定一个数组,一次可以给数组增加一个非负的元素,问最少需要增加多少次,可以使数组满足:数组元素之和等于数组的长度

思路:枚举初始给定数组之和。
若小于数组长度,则再增加一个整数即可(肯定存在这样的一个正数);
若等于数组长度,则不用添加元素;
若大于数组长度,则需要添加(数组之和减数组长度)个0.

代码:

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <iterator>
#include <vector>
#include <cstring>
#include <string>
#include <cmath>
#include <deque>
#include <queue>
#include <map>
#include <unordered_map>
#include <set>
#include <stack>

using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define endl "\n"
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define debug(x) cout<<"**"<<x<<"**"<<endl
#define mem(a, b) memset(a, b, sizeof a)
const double eps = 1e-6; 
const double pi = acos(-1.0);
const int mod = 1000000007;
const int N = 1e4 + 10;


int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    IOS
    
    int T; cin>>T;
    while(T--)
    {
        int n; cin>>n;
        ll sum = 0, ans;
        for(int i = 0; i < n; i++) 
        {
            int x; cin>>x;
            sum += x;
        }
        if(sum < n) ans = 1;
        else if(sum == n) ans = 0;
        else ans = sum-n;
        cout<<ans<<endl;
    }
    return 0;
}

B-Bad Boy

题意:一个人站在n×m的方格中(x, y)处,让你在方格中挑选两个位置放置两个悠悠球,然后这个人去捡悠悠球再回到原位置,问这两个悠悠球放在哪能让他走的路程最大。

思路:第一个球放在离他现在位置最远的地方,第二个球放在离第一个球最远的位置(其实就是某两个顶点处)

代码:

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <iterator>
#include <vector>
#include <cstring>
#include <string>
#include <cmath>
#include <deque>
#include <queue>
#include <map>
#include <unordered_map>
#include <set>
#include <stack>

using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define endl "\n"
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define debug(x) cout<<"**"<<x<<"**"<<endl
#define mem(a, b) memset(a, b, sizeof a)
const double eps = 1e-6; 
const double pi = acos(-1.0);
const int mod = 1000000007;
const int N = 1e4 + 10;


int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    IOS
    
    int T; cin>>T;
    while(T--)
    {
        int n, m, xx, yy;
        int x1, y1, x2, y2;
        cin>>n>>m>>xx>>yy;
        if(xx <= (n+1)/2) x1 = n;
        else x1 = 1;
        if(yy <= (m+1)/2) y1 = m;
        else y1 = 1;
        if(x1 == n) x2 = 1;
        else x2 = n;
        if(y1 == m) y2 = 1;
        else y2 = m;
        cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<endl;
    }
    return 0;
}

C-Challenging Cliffs

题意:给定一个数组,每个数组元素代表一座山,值代表高度。从i -> i+1, 如果 h i < = h i + 1 h_{i} <= h_{i+1} hi<=hi+1,则贡献值加1。让你重新排列数组,找出贡献值最大的排列,同时还要满足数组第一个值和最后一个值的差值是最小的。

思路:排个序。找出最小差值,然后按照排序之后的顺序分段输出即可保证贡献值最大。

代码:

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <iterator>
#include <vector>
#include <cstring>
#include <string>
#include <cmath>
#include <deque>
#include <queue>
#include <map>
#include <unordered_map>
#include <set>
#include <stack>

using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define endl "\n"
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define debug(x) cout<<"**"<<x<<"**"<<endl
#define mem(a, b) memset(a, b, sizeof a)
const double eps = 1e-6; 
const double pi = acos(-1.0);
const int mod = 1000000007;
const int N = 1e4 + 10;


int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    IOS
    
    int T; cin>>T;
    while(T--)
    {
        int n; cin>>n;
        int a[n+1];
        for(int i = 1; i <= n; i++) cin>>a[i];
        sort(a+1, a+n+1);
        int minn = a[2]-a[1], id = 1;
        for(int i = 3; i <= n; i++)
        {
            if(a[i]-a[i-1] < minn)
            {
                minn = a[i]-a[i-1];
                id = i-1; 
            }
        }
        cout<<a[id]<<" ";
        for(int i = id+2; i <= n; i++) cout<<a[i]<<" ";
        for(int i = 1; i < id; i++) cout<<a[i]<<" ";
        cout<<a[id+1]<<endl;
    }
    return 0;
}

D-Deleting Divisors

题意:Alice和Bob在玩游戏,Alice和Bob又在玩游戏,Alice和Bob总在玩游戏(o_o)
给定一个数字n,每次可以拿走一个n的除数(不能是1或n),n相应减少。无法再拿走除数时就输。Alice先手。

(参考了这位的博客:链接
思路:博弈论嘛,先分析出必败态为最后剩下一个质数(质数除了2都是奇数)。然后枚举情况(可以打表观察规律,这样推规律的时候就会方向清晰一点)

一、Alice先手拿到偶数。
(1)这个偶数由奇数*偶数组成:在最优选择下,Alice会减一个奇数的除数,剩下一个奇数给Bob,Bob只能减奇数的除数(因为没有偶数的除数),剩下一个偶数给Alice,开始循环。。。则Alice必胜
(2)这个偶数由偶数*偶数组成(可以表示为 2 n 2^{n} 2n):在最优选择下,Alice会选择减去 2 n − 1 2^{n-1} 2n1,剩下 2 n − 1 2^{n-1} 2n1给Bob(不这样减的话,Bob一定拿到奇数*偶数,则Bob就一定赢),Bob也同样会继续选择减去 2 ( n − 1 ) − 1 2^{(n-1)-1} 2(n1)1。那么最终状态就是:如果n是偶数,则Bob拿到2,Bob输;如果n是奇数,则Alice拿到2,Alice输。

二、Alice先手拿到奇数
Alice只能减去一个奇数的除数,则Bob拿到由奇数*偶数组成的偶数,即Alice必输。

代码:

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <iterator>
#include <vector>
#include <cstring>
#include <string>
#include <cmath>
#include <deque>
#include <queue>
#include <map>
#include <unordered_map>
#include <set>
#include <stack>

using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define endl "\n"
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define debug(x) cout<<"**"<<x<<"**"<<endl
#define mem(a, b) memset(a, b, sizeof a)
const double eps = 1e-6; 
const double pi = acos(-1.0);
const int mod = 1000000007;
const int N = 1e4 + 10;


int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    IOS
    
    int T; cin>>T;
    while(T--)
    {
        int n; cin>>n;
        if(n&1) cout<<"Bob"<<endl;
        else
        {
            int cnt = 0;
            while(n%2 == 0)
            {
                n /= 2;
                cnt++;
            }
            if(n != 1) cout<<"Alice"<<endl;
            else
            {
                if(cnt&1) cout<<"Bob"<<endl;
                else cout<<"Alice"<<endl;
            }
        }
    }
    return 0;
}

E-Erase and Extend (Easy Version)

题意:给定一个长度为n的字符串s,可以无限次进行两种操作:删除最后一个元素或者使s = s+s。求通过这两种操作,可以得到的长度为k的最小的字符串。

思路:建议先看一遍代码。最终的答案肯定是s的一个前缀子串的重复。然后证明这种做法的合理性:(cnt代表:从s[0]开始的,最终结果中的前缀子串的长度)。纯证明肯定是没有举栗子更好理解。

(1)s[i] > s[i%cnt]
第i个元素比前缀子串中对应位置的元素大,显而易见该结束了
举个栗子:dcadcb 这种情况就是:目前的最优字串为dca,然后遇到了b,b>a,如果结束,最优字串重复为:dcadcadca,否则就是:dcadcbdca。肯定前面的是要小的,所以说明确实该结束了。

(2)s[i] < s[i%cnt]
第i个元素比最优前缀中对应位置的元素小,那就说明最优字串可以扩充s[i]。
举个栗子:dcbdca 这种情况就是:目前的最优字串为dcb,然后遇到了a,a<b,如果扩充,最优字串重复就是 dcbdcadcbdca,否则就是 dcbdcbdcbdcb,肯定是前面小,所以最优字串应该扩充

(3)s[i] == s[i%cnt]
这种情况是不能break的。因为不知道s[i+1]和s[(i+1)%cnt]的大小情况。
举个栗子:dbda ,等于说现在到了第二个d的位置,现在最优字串是db,如果break,第一种情况的答案就是dbdbdbdb,和dbdadbda的比较,显见是不能break;
再举个栗子:dbdc,和上面差不多,break后就是dbdbdbdb,和dbdcdbdc比较确实是更优的。
综上所述不能break。同样的道理,也不能更新最优字串到s[i]。

大家举举栗子就会发现很好理解。
代码:

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <iterator>
#include <vector>
#include <cstring>
#include <string>
#include <cmath>
#include <deque>
#include <queue>
#include <map>
#include <unordered_map>
#include <set>
#include <stack>

using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define endl "\n"
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define debug(x) cout<<"**"<<x<<"**"<<endl
#define mem(a, b) memset(a, b, sizeof a)
const double eps = 1e-6; 
const double pi = acos(-1.0);
const int mod = 1000000007;
const int N = 1e4 + 10;


int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    IOS
    
    int n, k; cin>>n>>k;
    string s; cin>>s;
    int cnt = 1;
    for(int i = 0; i < n; i++)
    {
        if(s[i] > s[i%cnt]) break;
        if(s[i] < s[i%cnt]) cnt = i+1;
    }
    for(int i = 0; i < k; i++) cout<<s[i%cnt];
    return 0;
}

F-Erase and Extend (Hard Version)

E的代码的时间复杂度是O(n),可以直接过F。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值