Codeforces Round #733 (Div. 1 + Div. 2)
Codeforces Round #733 (Div. 1 + Div. 2)
A - Binary Decimal
定義好數為各位是\(0\)或者\(1\)的十進位制數。
給出數\(n\),求出最少的好數的數量,使得這些好數相加恰好為\(n\)
對於\(100\%\)的資料滿足\(1 \leq n \leq 10^9\)
注意到,十進位制數的減法是按位減去,增加一個好數,意味著將\(n\)各位上減去這個好數對應位子上的\(0\)或者\(1\)
最終情況是\(n\)各個位置上的數都為\(0\),因此最少的好數的數量等於\(n\)各個數位上的數值的最大值。
時間複雜度\(O(lg n)\)
# include <bits/stdc++.h> using namespace std; int a[10]; int main() { int t; scanf("%d",&t); while (t--) { int n; scanf("%d",&n); int ans=0; while (n) { ans=max(ans,n%10); n/=10; } printf("%d\n",ans); } return 0; }
B - Putting Plates
\(n\times m\)的桌子,只有邊緣處才能放盤子\(1\),否則是\(0\)。
且兩個盤子不能相鄰擺放,求出放最多盤子時的方案。
對於\(100\%\)的資料滿足\(3 \leq n,m \leq 20\)
分\(n,m\)奇偶性情況討論即可。
時間複雜度\(O(nm)\)
# include <bits/stdc++.h> using namespace std; int a[25][25]; int main() { int t; scanf("%d",&t); while (t--) { int n,m; scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) a[i][j]=0; if ((n&1)&&(m&1)) { for (int i=1;i<=m;i+=2) a[1][i]=1,a[n][i]=1; for (int i=1;i<=n;i+=2) a[i][1]=1,a[i][m]=1; } else if (n%2==0&&m%2==0) { for (int i=2;i<=m-1;i+=2) a[1][i]=1; for (int i=m-1;i>=2;i-=2) a[n][i]=1; for (int i=2;i<=n-1;i+=2) a[i][m]=1; for (int i=n-1;i>=2;i-=2) a[i][1]=1; } else if (n%2==1&&m%2==0) { for (int i=2;i<=m;i+=2) a[1][i]=1; for (int i=1;i<=m-1;i+=2) a[n][i]=1; for (int i=n;i>=2;i-=2) a[i][1]=1; for (int i=1;i<=n-1;i+=2) a[i][m]=1; } else { for (int i=1;i<=m-1;i+=2) a[1][i]=1; for (int i=m;i>=2;i-=2) a[n][i]=1; for (int i=1;i<=n;i+=2) a[i][1]=1; for (int i=2;i<=n;i+=2) a[i][m]=1; } for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) printf("%d",a[i][j]); puts(""); } } return 0; }
C - Pursuit
一場比賽由若干輪組成,每輪會有一個得分\(w\in[0,100]\)。
第\(k\)輪比賽後的得分為之前輪次的最高的\(k-\lfloor \frac{k}{4} \rfloor\)個分數之和。
\(A,B\)進行了\(n\)輪比賽,每輪的得分分別為\(a_i,b_i\)
詢問至少再過多少輪比賽\(A\)得分有可能大於等於\(B\)的得分。
對於\(100\%\)的資料\(1 \leq n\leq 10^5\)
本題答案具有單調性,先二分這個答案。
check答案是否合法的時候可以貪心,\(A\)在後面的比賽中全部獲得\(100\)分,\(B\)在後面的比賽中全部獲得\(0\)分。
時間複雜度為\(O(n log_2^2 n)\)
# include <bits/stdc++.h>
# define int long long
using namespace std;
const int N=3e5+10;
int a[N],aa[N],b[N],bb[N],n;
bool check(int x) {
for (int i=1;i<=n;i++) {
a[i]=aa[i]; b[i]=bb[i];
}
for (int i=n+1;i<=n+x;i++) a[i]=100;
for (int i=n+1;i<=n+x;i++) b[i]=0;
sort(a+1,a+1+n+x); reverse(a+1,a+1+n+x);
sort(b+1,b+1+n+x); reverse(b+1,b+1+n+x);
x=(n+x)-(n+x)/4;
int res1=0; for (int i=1;i<=x;i++) res1+=a[i];
int res2=0; for (int i=1;i<=x;i++) res2+=b[i];
return res1>=res2;
}
signed main()
{
int t; scanf("%lld",&t);
while (t--) {
scanf("%lld",&n);
for (int i=1;i<=n;i++) scanf("%lld",&aa[i]);
for (int i=1;i<=n;i++) scanf("%lld",&bb[i]);
int l=0,r=2*n,ans;
while (l<=r) {
int mid=(l+r)/2;
if (check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%lld\n",ans);
}
return 0;
}
D - Secret Santa
給出\(n\)個數字\(a_i\),且保證\(a_i\ne i\)
求一個排列\(b_i\)滿足\(b_i\ne i\) 且\(a_i = b_i\)的值儘量多。
對於\(100\%\)的資料滿足\(2 \leq n \leq 2\times 10^5\)
可以證明最終\(a_i = b_i\)儘量多的最終值為\(a_i\)中不同元素個數。
必要性顯然,下面給出一個構造方案說明充分性:
首先對於每一個\(i\),建一條$i \(到\)a_i$的有向邊。然後對有有多個進入該點的邊任意保留一條。
將這些邊上的點,設為已經加入圖中。
下面對於未加入圖中的點\(i\)處理。
找到\(a_i\),並求出\(a_i\)為目標的唯一一條邊連線的點\(u\),保留\(i\)到\(a_i\)的邊,把\(u\)到\(a_i\)的邊改為\(u\)到\(i\)的邊。
這樣,增加一個滿足\(a_i=b_i\),又減少一個滿足\(a_i = b_i\)的點。
由於按照這樣構造,每個點\(i\)有且只有一個出邊,\(b_i\)構造完成。
時間複雜度為\(O(n)\)
# include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
map<int,int>mp;
vector<int>in[N];
int a[N],ans[N];
int main() {
int t; scanf("%d",&t);
while (t--) {
int n; scanf("%d",&n);
mp.clear();
for (int i=1;i<=n;i++) in[i].clear(),ans[i]=0;
for (int i=1;i<=n;i++) {
scanf("%d",&a[i]);
mp[a[i]]=1; in[a[i]].push_back(i);
}
for (int i=1;i<=n;i++) if (in[i].size()) {
ans[in[i][0]]=i;
}
for (int i=1;i<=n;i++) if (in[i].size()==0) {
int u=i,v=i; while (ans[v]) v=ans[v];
if (u==v) continue;
ans[v]=u;
}
for (int i=1;i<=n;i++) if (!ans[i]) {
ans[i]=a[i]; ans[in[a[i]][0]]=i; in[a[i]][0]=i;
}
printf("%d\n",mp.size());
for (int i=1;i<=n;i++) printf("%d ",ans[i]);
puts("");
}
return 0;
}
E - Minimax
一個字串\(s\),每個位置\(i\)有函式\(f(i)\),其值其字首和字尾(長度不能是\(i\))重合的最大距離。
而\(g(s) = min_{i=1}^{len(s)} f(i)\)。
重新排列\(s\)中字母時,要求字典序最小的構造\(s\)字串的方案,使得\(g(s)\)的值最小。
對於\(100\%\)的資料\(1 \leq |s|\leq 10^5\)
分類討論:
- 當字母數只有\(1\)種時,輸出原字串即可。
- 當存在一個字元只出現一次時,將這種字元中字典序最小的放在首位,後面排序即可,答案為\(0\)
- 當所有字元出現都大於等於\(2\)次,
- 當字母數只有\(2\)種時,不妨設字典序較小的字元為\(a\),字典序較大的字元為\(b\)
- 當\(a\)的數目足夠少,答案為\(1\),\(aabababab...abbbb\)。
- 當\(a\)的數目不多也不少的時候,答案為\(1\),\(aababab...aba\)。
- 當\(a\)的數目足夠多,答案為\(1\),\(abbb...bbbaa...aa\)。
- 當字母數大於等於\(3\)時,
- 當\(a\)的數目足夠少時,答案為\(1\), \(aabababacacadddeeefff...\)
- 當\(a\)的數目足夠多時,答案為1,\(abaaa...aaacbbb...bccc...cddd...\)
- 當字母數只有\(2\)種時,不妨設字典序較小的字元為\(a\),字典序較大的字元為\(b\)
時間複雜度為\(O(|s|)\)
# include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
char s[N];
int c[27];
void solve(){
int cnt=0,l=0;
for (int i=0;i<26;i++) if (c[i]==1) {
putchar(i+'a'); c[i]--;
for (int j=0;j<26;j++)
for (int k=1;k<=c[j];k++)
putchar(j+'a');
return;
} else if (c[i]>1) cnt++,l+=c[i];
if (cnt==1) {
printf("%s",s);
}else if (cnt==2) {
int p1=-1,p2=-1;
for (int i=0;i<26;i++) if (c[i]) {
if (p1==-1) p1=i; else p2=i;
}
if (c[p1]<=(l+1)/2) {
putchar(p1+'a');
for (int i=2;i<=c[p1];i++) putchar(p1+'a'),putchar(p2+'a');
for (int i=c[p1];i<=c[p2];i++) putchar(p2+'a');
} else if (c[p1]<=l/2+1){
putchar(p1+'a');
for (int i=3;i<=c[p1];i++) putchar(p1+'a'),putchar(p2+'a');
putchar(p1+'a');
} else {
putchar(p1+'a');
for (int i=1;i<=c[p2];i++) putchar(p2+'a');
for (int i=2;i<=c[p1];i++) putchar(p1+'a');
}
} else {
int ps=-1;
for (int i=0;i<26;i++) if (c[i]) {
ps=i; break;
}
if (c[ps]<=(l+1)/2) {
vector<char>tmp; tmp.clear();
for (int i=0;i<26;i++) if (i!=ps) {
for (int j=1;j<=c[i];j++) tmp.push_back(i+'a');
}
putchar(ps+'a');
int res=c[ps]-1;
for (int i=0;i<tmp.size();i++) {
if (res) putchar(ps+'a');
putchar(tmp[i]);
if (res) res--;
}
} else if (c[ps]-1<=l/2) {
vector<char>tmp; tmp.clear();
for (int i=0;i<26;i++) if (i!=ps) {
for (int j=1;j<=c[i];j++) tmp.push_back(i+'a');
}
putchar(ps+'a');
int res=c[ps]-1;
for (int i=0;i<tmp.size();i++) {
if (res) putchar(ps+'a');
putchar(tmp[i]);
if (res) res--;
}
putchar(ps+'a');
} else {
int p1=-1,p2=-1,p3=-1;
for (int i=0;i<26;i++) if (c[i]) {
if (p1==-1) p1=i;
else if (p2==-1) p2=i;
else if (p3==-1) p3=i;
}
putchar(p1+'a'); putchar(p2+'a');
for (int i=2;i<=c[p1];i++) putchar(p1+'a');
putchar(p3+'a');
for (int i=2;i<=c[p2];i++) putchar(p2+'a');
for (int i=2;i<=c[p3];i++) putchar(p3+'a');
for (int i=0;i<26;i++) if (i>p3) {
for (int j=1;j<=c[i];j++) putchar(i+'a');
}
}
}
}
int main() {
int t; scanf("%d",&t);
while (t--) {
scanf("%s",s); int l=strlen(s);
for (int i=0;i<26;i++) c[i]=0;
for (int i=0;i<l;i++) c[s[i]-'a']++;
solve();
puts("");
}
return 0;
}