1. 程式人生 > >Codeforces Round #513 遊記

Codeforces Round #513 遊記

之間 偶數 cpp class -i num 給定 a+b vector

Codeforces Round #513 遊記

A - Phone Numbers

題目大意:

電話號碼是8開頭的\(1\)位數字。告訴你\(n(n\le100)\)個數字,每個數字至多使用一次。問最多能湊出多少個電話號碼。

思路:

統計8出現的次數,如果有多余的8不能作為開頭,那麽就將其放到後面去

源代碼:

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
inline int getdigit() {
    register char ch;
    while(!isdigit(ch=getchar()));
    return ch^'0';
}
int cnt[2];
int main() {
    const int n=getint();
    for(register int i=0;i<n;i++) cnt[getdigit()==8]++;
    while(cnt[0]<cnt[1]*10) {
        cnt[1]--;
        cnt[0]++;
    }
    printf("%d\n",std::min(cnt[1],cnt[0]/10));
    return 0;
}

B - Maximum Sum of Digits

題目大意:

定義\(S(x)\)\(x\)各數位之和。給定\(n(n\le10^{12})\)\(a+b=n\),求\(S(a)+S(b)\)的最大值。

思路:

如果這一位\(x\)不是第一位,且這一位不是\(9\),就把這一位當做\(10+x\),並把上一位\(-1\)

源代碼:


 #include<cstdio>
#include<cctype>
typedef long long int64;
inline int64 getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int64 x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
int main() {
    int64 n=getint();
    int ans=0;
    for(;n;n/=10) {
        ans+=n%10;
        if(n%10!=9&&n/10!=0) {
            ans+=10;
            n-=10;
        }
    }
    printf("%d\n",ans);
    return 0;
}

C - Maximum Subrectangle

題目大意:

給定\(a_{1\sim n},b_{1\sim m}(n,m\le2000)\)\(x\)\(c_{i,j}=a_ib_j\)。求\(c\)的一個最大子矩陣,使得矩陣內數字和\(\le x\)。輸出面積的最大值。

思路:

預處理\(a/b\)連續\(i\)個數之和的最小值。然後枚舉矩形長寬即可。

源代碼:

#include<cstdio>
#include<cctype>
#include<climits>
#include<algorithm>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
typedef long long int64;
const int N=2001;
int a[N],b[N],min1[N],min2[N];
int main() {
    const int n=getint(),m=getint();
    for(register int i=1;i<=n;i++) a[i]=getint();
    for(register int i=1;i<=m;i++) b[i]=getint();
    const int x=getint();
    for(register int i=1;i<=n;i++) {
        min1[i]=INT_MAX;
        int sum=0;
        for(register int j=1;j<i;j++) sum+=a[j];
        for(register int j=i;j<=n;j++) {
            sum-=a[j-i];
            sum+=a[j];
            min1[i]=std::min(min1[i],sum);
        }
    }
    for(register int i=1;i<=m;i++) {
        min2[i]=INT_MAX;
        int sum=0;
        for(register int j=1;j<i;j++) sum+=b[j];
        for(register int j=i;j<=m;j++) {
            sum-=b[j-i];
            sum+=b[j];
            min2[i]=std::min(min2[i],sum);
        }
    }
    int ans=0;
    for(register int i=1;i<=n;i++) {
        for(register int j=1;j<=m;j++) {
            if((int64)min1[i]*min2[j]<=x) {
                ans=std::max(ans,i*j);
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

D - Social Circles

題目大意:

\(n(n\le10^5)\)個人排成一圈,第\(i\)個人要求自己左邊空出\(l_i\)個座位,右邊空出\(r_i(l_i,r_i\le10^9)\)個座位。問最少需要安排多少個座位。

思路:

一開始先假設每個人都占了\(l_i+r_i+1\)個位置。考慮怎樣安排相鄰人的順序,並合並相鄰人的\(l_i,r_i\)使得答案最優。

將所有\(l_i,r_i\)分別排序,將對應的\(l_i,r_i\)合並一定是最優的(想一想這是為什麽)。

源代碼:

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
typedef long long int64;
const int N=1e5+1;
int l[N],r[N];
int main() {
    const int n=getint();
    int64 ans=0;
    for(register int i=1;i<=n;i++) {
        l[i]=getint();
        r[i]=getint();
        ans+=l[i]+r[i]+1;
    }
    std::sort(&l[1],&l[n]+1);
    std::sort(&r[1],&r[n]+1);
    for(register int i=1;i<=n;i++) {
        ans-=std::min(l[i],r[i]);
    }
    printf("%lld\n",ans);
    return 0;
}

E - Sergey and Subway

題目大意:

給定一棵\(n(n\le2\times10^5)\)個點的樹,每條邊權都是\(1\)。原樹上的邊稱作老邊,兩個點之間可以連一條新邊當且僅當原來兩個點之間距離為\(2\)。問最後所有點對之間最短路之和是多少?

思路:

首先不考慮新邊,我們可以考慮每條邊的貢獻計算出所有點對距離值和\(sum\)

而經過加新邊的操作後,原來距離為偶數的點對距離\(/2\),奇數點對距離\(/2+1\)。而我們可以通過黑白染色後黑/白點的數目統計出奇數距離的點對數目。

源代碼:

#include<cstdio>
#include<cctype>
#include<vector>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
using int64=long long;
const int N=2e5+1;
std::vector<int> e[N];
inline void add_edge(const int &u,const int &v) {
    e[u].push_back(v);
    e[v].push_back(u);
}
int64 ans;
bool col[N];
int n,size[N],cnt[2],par[N];
void dfs(const int &x,const int &par) {
    size[x]=1;
    ::par[x]=par;
    cnt[col[x]=!col[par]]++;
    for(auto &y:e[x]) {
        if(y==par) continue;
        dfs(y,x);
        size[x]+=size[y];
        ans+=(int64)size[y]*(n-size[y]);
    }
}
int main() {
    n=getint();
    for(register int i=1;i<n;i++) {
        add_edge(getint(),getint());
    }
    dfs(1,0);
    ans=(ans+(int64)cnt[0]*cnt[1])/2;
    printf("%lld\n",ans);
    return 0;
}

Codeforces Round #513 遊記