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

連接:http://codeforces.com/contest/1043c++


A - Elections - [水水水水題]

題意:spa

我和另外一我的競爭選舉,共有 $n$ 我的投票,每一個人手上有 $k$ 票,必須投給我或者另外一我的。指針

如今已知每一個人給另外一我的投 $a_i$ 票,也就是說會給我投 $k-a_i$ 票。求最小的整數 $k$,使得個人票數嚴格大於另外一我的。code

題解:blog

暴力枚舉 $k$。排序

AC代碼:ci

#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}$。get

如今又有一個長度爲 $n+1$ 的序列 $a_0,a_1,a_2, \cdots, a_n$,已知這個序列是經過 $a_i = x_{(i-1) \bmod 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 - (Done)

題意:

如今共有兩道題目,有 $n$ 我的,每一個人作第一題會獲得 $x$ 的罰時,作第二題會獲得 $y$ 的罰時。

他們要兩兩相互組隊,組隊以後隊裏的兩我的會一人挑一題作(固然是罰時越小越好),他們在這一輪會獲得他們隊的總罰時分數。

又知道,有 $m$ 個組是不能組的(這兩我的不想組一起),如今要求每一個人最後會獲得的分數。

題解:

直接上 $O(n^2)$ 地算是不現實的。考慮作減法,不妨先無論 $m$ 組人不想組隊的狀況,直接算出每一個人和其餘全部人組隊,最後會獲得多少分,再減去 $m$ 組不能組的分數便可。

考慮如何計算第 $i$ 我的,和其餘全部人分別組隊後獲得的分數。先將全部人按 $x_i - y_i$ 排序,這樣一來,對於第 $i$ 我的,

其前面的任意一我的 $j$ 都知足 $x_j - y_j \le x_i - y_i \Rightarrow x_j + y_i \le x_i + y_j$;也就是說,第 $i$ 我的和其前面的人組隊,他本人必然會作 $y_i$ 這道題。

其後面的任意一我的 $k$ 都知足 $x_i - y_i \le x_k - y_k \Rightarrow x_i + y_k \le x_k + y_i$;也就是說,第 $i$ 我的和其後面的人組隊,他本人必然會作 $x_i$ 這道題。

這樣一來,咱們只要 $O(n)$ 求出 $x_j$ 的前綴和以及 $y_k$ 的後綴和,而後便可 $O(1)$ 獲得第 $i$ 我的的總分數。

最後減去那 $m$ 組人不想組隊的狀況便可。

AC代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=3e5+10;
int n,m;
struct P{
    int id;
    ll x,y;
    P(){}
    P(int _id,ll _x,ll _y){id=_id, x=_x, y=_y;}
    bool operator<(const P& oth) {
        return x-y < oth.x-oth.y;
    }
}p[maxn];
pii hate[maxn];
ll xpre[maxn],ysuf[maxn];
ll ans[maxn];
int main()
{
    cin>>n>>m;
    for(int i=1,x,y;i<=n;i++) scanf("%d%d",&x,&y), p[i]=P(i,x,y);
    for(int i=1;i<=m;i++) scanf("%d%d",&hate[i].first,&hate[i].second);
    memset(ans,0,sizeof(ans));
    for(int i=1,a,b;i<=m;i++)
    {
        a=hate[i].first, b=hate[i].second;
        ll des=min(p[a].x+p[b].y,p[a].y+p[b].x);
        ans[hate[i].first]-=des;
        ans[hate[i].second]-=des;
    }
    sort(p+1,p+n+1);

    xpre[0]=0;
    for(int i=1;i<=n;i++) xpre[i]=xpre[i-1]+p[i].x;
    ysuf[n+1]=0;
    for(int i=n;i>=1;i--) ysuf[i]=ysuf[i+1]+p[i].y;

    for(int i=1;i<=n;i++) {
        ans[p[i].id]+=xpre[i-1]+(i-1)*p[i].y+ysuf[i+1]+(n-i)*p[i].x;
    }
    for(int i=1;i<=n;i++) printf("%lld%c",ans[i],i==n?'\n':' ');
}

 


F - Make It One - [莫比烏斯反演] - (Undone)

題意:

給出 $n(1 \le n \le 3e5)$ 個數字 $a_1 \sim a_n(1 \le a_i \le 3e5)$,要求選取最少的若干個數字,使他們的最大公因數爲 $1$。

題解:

相關文章
相關標籤/搜索