Codeforces Round #493 DIV2

A - Balloons

只有一堆的时候显然不可以。
两堆的时候,如果他们数量相等,也不可以。
其他情况,为了保险起见,我把他们排一下序,选择数量最少的那堆。其实只要不选数量最大的那堆就可以了。

#include <bits/stdc++.h>

using namespace std;
int n;
struct node
{
    int a,b;
}p[100];

bool cmp(node aa,node bb)
{
    return aa.a < bb.a;
}

int main()
{
    int tot = 0;
    scanf("%d",&n);
    for (int i=1;i<=n;i++){
        scanf("%d",&p[i].a);
        tot += p[i].a;
        p[i].b=i;
    }
    sort(p+1,p+1+n,cmp);
    if (n == 1){
        printf("-1\n");
    }else if (n == 2 && p[1].a == p[2].a)
    {
        printf("-1\n");
    }else
    {
        printf("1\n%d\n",p[1].b);
    }
    return 0;
}

B - Cutting

因为切完后的每一段里面都是符合要求的,那么如果倒推回去,它也是符合要求的,所以切的顺序不影响结果。
那么可以直接把能切的地方选出来,按花费排个序,选择花费小的就可以了。

include <bits/stdc++.h>

using namespace std;
const int MAXN = 1010;
int a[MAXN],even[MAXN],odd[MAXN];
int n,b;
vector<int> v;

int main()
{
    scanf("%d%d",&n,&b);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        even[i] = even[i-1];
        odd[i] = odd[i-1];
        if (a[i] % 2 == 0) even[i] ++;
        else odd[i]++;
    }
    for (int i=1;i<=n;i++)
    {
        if (even[i] == odd[i] && i!=1 && i!=n)
        {
            v.push_back( abs(a[i+1] - a[i]) );
        }
    }
    sort(v.begin(),v.end());
    int sz = v.size();
    int tot = 0,ans = 0;
    for (int i=0;i<v.size();i++)
    {
        if (tot + v[i] > b) break;
        tot += v[i];
        ans = i+1;
    }
    printf("%d\n",ans);
    return 0;
}

C - Convert to Ones

第二个操作是变成1所必须的,那么第一个操作对优化结果有什么帮助呢?
它可以把两段原本分开的0接到一起,比如把010变成100,从而用一次第二种操作就能变完两段,但这样也是要付出代价的,就是要花费一次第一种操作。如果不翻转,那么就要花费两次第二种操作。
这样一来一去,其实价格差就产生在一次第一种操作和一次第二种操作之间。选择一种便宜的就可以了。
其实连续的0和连续的1和单个的0和1的产生的花费是一样的,为了方便计算,我把他们都变成了单个的。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN = 400000;
char s[MAXN];
deque<char> que;
int n;
ll x,y,cnt,ans;


int main()
{
    scanf("%d%I64d%I64d",&n,&x,&y);
    getchar();
    for (int i=1;i<=n;i++)
    {
        scanf("%c",&s[i]);
        if (s[i] != s[i-1]) que.push_back(s[i]);
    }
    while (!que.empty() && que.front() == '1' ) que.pop_front();
    while (!que.empty() && que.back() == '1') que.pop_back();
    if ( que.size() == 1 || que.size() == 2)
    {
        printf("%I64d\n",y);
    }else if (que.size() == 0)
    {
        printf("0\n");
    }else
    {
        ll cnt = que.size()/ 2;
        ans = min(x,y) * cnt + y;
        printf("%I64d\n",ans);
    }
    return 0;
}

D - Roman Digits

这题一看到这么大的数字,果断先打表找规律,在OEIS查了一下后无果。
然而打表能打出来的数字又太少,看不出什么规律。
于是我简化了一下题目,把4个数字变成3个数字,希望多打一些数据出来,看看能不能找到规律。
结果还真发现了,当n足够大的时候,n+1的答案和n的答案之差不改变了。
然后写代码就是顺手的事了。2333。。

#include <bits/stdc++.h>

using namespace std;
int arr[]={4,10,20,35,56,83,116,155,198,244,292};
int n;
int main()
{
    cin >> n;
    if (n <= 11 )
    {
        printf("%d\n",arr[n-1]);
    }else
    {
        long long ans = 292 + 1ll * (n - 11) * 49;
        printf("%I64d",ans);
    }
    return 0;
}

E - Sky Full of Stars

最后没剩多少时间做这题,大致想想了,应该是个容斥的题目。
因为没怎么做过容斥的题目,所以想的很混乱,最后时间不够了。
之后参考了dalao的解答,大致的想法理解了,但是在容斥的过程上还是有些不懂,过几天多做点容斥的题目之后回来再理解一遍。
大致理解如下:
首先反过来考虑,找不幸运的组合,因为这样便于容斥。
要把列和行分开考虑。
首先排除掉列上出现相同的情况,也就是 ( 3 n 3 ) n 种,这个也就是容斥里开始时最大的范围,显然还包括了一些行上相同的情况,所以下面开始容斥。
列上不出现相同情况下,行出现相同的情况要分两类讨论,
1. 那些整行出现的同一颜色的行的颜色完全相同,比如有三行出现整行颜色一样,并且都是绿,这种情况列上的颜色不能和他们相同,有 3 C n i ( 3 n i 1 ) n 种。
2. 那些整行出现的同一颜色的行的颜色不完全相同,比如有三行出现整行颜色一样,但他们分别是红黄蓝,这种情况,列上就可以随便选了,有 ( 3 i 3 ) C n i 3 ( n i ) n
最终使用容斥。 a n s = 3 n 2 ( 3 n 3 ) n Σ i = 1 n ( 1 ) i C n i ( 3 ( 3 n i 1 ) n + ( 3 i 3 ) 3 ( n i ) n )
PS:逆元可以用O(n)的复杂度全部处理完,方法是先算一个fact[n]的逆元,那么fact[n-1]的逆元就是invfact[n-1] = invfact[n] * n % mod

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN = 1e6+100;
const ll mod = 998244353;

ll n,n2,fact[MAXN],invfact[MAXN];

ll qpow(ll a,ll k)
{
    ll ans = 1, tmp = a;
    while (k)
    {
        if (k&1) ans = ans * tmp  % mod;
        tmp = tmp * tmp % mod;
        k >>= 1;
    }
    return ans;
}

int main()
{
    scanf("%I64d",&n);
    fact[1] = 1;
    for (int i=2;i<=n;i++) fact[i] = fact[i-1] * i % mod;
    invfact[n] = qpow(fact[n],mod-2);
    for (int i=n-1;i>=0;i--) invfact[i] = invfact[i+1] * (i+1) % mod;
    n2 = n*n;
    ll ans = qpow(3, n2) ;
    ll sub = qpow( qpow(3,n ) -3 ,n  );
    ll xishu = -1;
    for (int i=1;i<=n;i++)
    {
        ll tmp = fact[n] * invfact[i] % mod * invfact[n-i] % mod;
        ll other = ( 3ll * qpow( qpow(3, n-i) - 1  , n) % mod + (qpow(3,i) -3) * qpow(3, (n-i)*n ) % mod ) % mod;
        tmp = (tmp * other) % mod;
        sub = ((sub + tmp * xishu) + mod )% mod;
        xishu *= -1;
    }
    ans = ((ans - sub)%mod + mod) % mod;
    printf("%I64d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/z631681297/article/details/80889816