Codeforces 1043 - A/B/C/D/E/F - (Undone)

链接:http://codeforces.com/contest/1043


A - Elections - [水水水水题]

题意:

我和另一个人竞争选举,共有 $n$ 个人投票,每个人手上有 $k$ 票,必须投给我或者另一个人。

现在已知每个人给另一个人投 $a_i$ 票,也就是说会给我投 $k-a_i$ 票。求最小的整数 $k$,使得我的票数严格大于另一个人。

题解:

暴力枚举 $k$。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
int n,a[maxn];
int main()
{
    cin>>n;
    int mx=1,sum=0;
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]), mx=max(a[i],mx), sum+=a[i];
    for(int k=mx;;k++)
    {
        if(sum<n*k-sum)
        {
            printf("%d\n",k);
            break;
        }
    }
}

B - Lost Array - [简单数学题]

题意:

我手上有一个序列 $x_0,x_1, \cdots, x_{k-1}$。

现在又有一个长度为 $n+1$ 的序列 $a_0,a_1,a_2, \cdots, a_n$,已知这个序列是通过 $a_i = x_{(i-1) \mod k} + a_{i-1}$ 计算得到,其中 $i \ge 0$ 且 $a_0 = 0$。

现在序列 $x_0,x_1, \cdots, x_{k-1}$ 丢失了,但给你 $a_0,a_1,a_2, \cdots, a_n$,求可能的 $k(1 \le k \le n)$。

题解:

显然从 $a_1$ 到 $a_k$ 是可以用来直接确定 $x_0,x_1, \cdots, x_{k-1}$,而后面的 $a_{k+1} \sim a_n$ 可以用来判定是否矛盾,不矛盾就是可行的 $k$。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int n,a[maxn];
int x[maxn];
inline bool ok(int k)
{
    for(int i=1;i<=k;i++) x[i-1]=a[i]-a[i-1];
    for(int i=k+1;i<=n;i++) {
        if(a[i]!=x[(i-1)%k]+a[i-1]) return 0;
    }
    return 1;
}
int main()
{
    cin>>n;
    a[0]=0;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    vector<int> ans;
    for(int k=1;k<=n;k++) {
        if(ok(k)) ans.push_back(k);
    }
    printf("%d\n",ans.size());
    for(int i=0;i<ans.size();i++) printf("%s%d",i>0?" ":"",ans[i]);
}

C - Smallest Word - [简单模拟]

题意:

给出只包含字符 $a,b$ 的字符串 $s$,现在你从长度为 $1$ 到 $|s|$ 依次遍历所有的前缀子串,你可以选择反转这个前缀子串,或者不动。

现在要你输出 $|s|$ 个选择,使得最后的 $s$ 字典序最小。

题解:

从左到右遍历字符串,对于第 $i$ 个字符,始终保持 $1 \sim i-1$ 个字符保持 "$a,a,\cdots,a,b,b,\cdots,b$" 或者 "$b,b,\cdots,b,a,a,\cdots,a$" 这样的样式。

可以使得最后字符串为 "$a,a,\cdots,a,b,b,\cdots,b$"。

AC代码:

#include<bits/stdc++.h>
using namespace std;
string s;
int main()
{
    cin>>s;
    char pre=s[0];
    for(int i=1;i<s.size();i++)
    {
        if(s[i]=='a')
        {
            if(pre=='b') printf("1 "), pre='a';
            else printf("0 ");
        }
        if(s[i]=='b')
        {
            if(pre=='a') printf("1 "), pre='b';
            else printf("0 ");
        }
    }
    if(pre=='a') printf("1\n");
    else printf("0\n");
}

D - Mysterious Crime - [双指针维护]

题意:

给出 $m$ 个 $1 \sim n$ 的排列,求所有公共子串的数目。

题解:

换句话说,就是在第 $1$ 个排列里找,在其他 $2 \sim m$ 个排列里出现的所有公共子串。

不难想到,可以将第 $1$ 个排列分成若干段,每段都是不能在往右延伸的最长公共子串,例如:$(1,2,3,6,4,5)$ 和 $(4,5,6,1,2,3)$,则可以把第 $1$ 个排列分成 $(1,2,3),(6),(4,5)$。

因此用两根指针分别维护这些段的左右端点,每次找到一个长为 $len$ 的段,就产生贡献 $\frac{(len)(len+1)}{2}$。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int maxm=15;
int n,m;
int nxt[maxm][maxn];
int main()
{
    cin>>n>>m;
    memset(nxt,0,sizeof(nxt));
    for(int j=1;j<=m;j++)
    {
        for(int i=1,now,pre=0;i<=n;i++)
        {
            scanf("%d",&now);
            nxt[j][pre]=now;
            pre=now;
        }
    }

    ll ans=0;
    int len=1;
    for(int i=nxt[1][0],j;i;i=nxt[1][i])
    {
        for(j=2;j<=m;j++) {
            if(nxt[j][i]!=nxt[1][i]) break;
        }
        if(j>m && nxt[1][i]) len++;
        else ans+=(ll)len*(len+1)/2, len=1;
    }
    cout<<ans<<endl;
}

E - Train Hard, Win Easy - (Undone)


F - Make It One - (Undone)

猜你喜欢

转载自www.cnblogs.com/dilthey/p/9911343.html