Codeforces Round #513 遊記
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 遊記