[problem:379553A]
Author: wxhtzdy
Greedily take the smallest character in both strings. What's the exception to this?
We can't take the smallest character in both strings when we've already took $$$k$$$ elements from the string we chose. Denote $$$A$$$ as the number of characters we've took from string $$$a$$$ in the last few consecutive moves and denote $$$B$$$ the same for $$$b$$$. If $$$A=k$$$, then we have to take the smallest character in string $$$b$$$ instead of possibly $$$a$$$. If $$$B=k$$$, then we have to take the smallest character in string $$$a$$$ instead of possibly $$$b$$$.
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int t; cin>>t;
while (t--)
{
int n,m,k; cin>>n>>m>>k;
string a,b,c; cin>>a>>b;
sort(a.begin(),a.end(),greater<char>());
sort(b.begin(),b.end(),greater<char>());
int ak=0,bk=0;
while (!a.empty() && !b.empty())
{
bool gde=b.back()<a.back();
if (gde && bk==k) gde=0;
if (!gde && ak==k) gde=1;
if (gde) c.push_back(b.back()),bk++,ak=0,b.pop_back();
else c.push_back(a.back()),ak++,bk=0,a.pop_back();
}
cout<<c<<"\n";
}
}
[problem: 379553B]
Author: n0sk1ll
When is it impossible to find such permutation?
It is impossible only for $$$n=1$$$. In every other case, iterate over each position and take the smallest available number. What's the exception to this?
The exception is the last two elements. We can always take the smallest available number for each $$$q_i$$$ satisfying $$$i<n-1$$$. To do this we maintain an array of bools of already taken numbers, and then iterate over it to find the smallest available number satisfying $$$p_i\neq q_i$$$.
Now consider $$$(p_{n-1},p_{n})$$$ and we want $$$(q_{n-1},q_{n})$$$ to be lexicographically minimal. Let $$$a$$$ and $$$b$$$ be the last two unused numbers. It can be proven that at least one of the permutations ending with $$$(a,b)$$$ or $$$(b,a)$$$ will be valid. We just take the lexicographically minimal valid one.
This solution runs in $$$O(n^2)$$$ and can be optimized to $$$O(n \ log \ n)$$$.
#include <bits/stdc++.h>
using namespace std;
bool took[1005];
int p[1005];
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int t; cin>>t;
while (t--)
{
int n; cin>>n;
for (int i=1;i<=n;i++) cin>>p[i];
for (int i=1;i<=n;i++) took[i]=0;
if (n==1)
{
cout<<"-1\n";
continue;
}
for (int i=1;i<=n-2;i++)
{
int k=1;
while (took[k] || k==p[i]) ++k;
cout<<k<<" "; took[k]=1;
}
int a=-1,b=-1;
for (int i=1;i<=n;i++) if (!took[i])
{
if (a==-1) a=i;
else b=i;
}
if (a!=p[n-1] && b!=p[n]) cout<<a<<" "<<b<<"\n";
else cout<<b<<" "<<a<<"\n";
}
}
#include <bits/stdc++.h>
using namespace std;
int t,n,A[1010],B[1010];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&A[i]);
B[i] = i;
}
if(n==1)
{
printf("-1\n");
continue;
}
for(int i=1; i<n; i++)
{
if(A[i]==B[i]) swap(B[i],B[i+1]);
}
if(A[n]==B[n]) swap(B[n-1],B[n]);
for(int i=1; i<=n; i++) printf("%d ",B[i]);
printf("\n");
}
return 0;
}
Riblji_Keksic found the O(n) solution.
[problem:379553C]
Author: n0sk1ll
We always delete a vertex directly connected to an infected one.
Use dp.
Let $$$u_1,u_2,...,u_k$$$ be the sequence of removed vertices such that the infection cannot spread anymore. If vertex $$$u_i$$$ was never directly connected to an infected vertex, then we could have deleted its parent instead of $$$u_i$$$ and we would get a better solution. Hence, we may assume we always delete a vertex directly connected to an infected one.
Now we may use some dynamic programming ideas. Let $$$dp_i$$$ be the maximum number of vertices we can save in the subtree of vertex $$$i$$$. If $$$c_1$$$ and $$$c_2$$$ are the children of vertex $$$i$$$, the transition is
where $$$s_i$$$ denotes the number of vertices in the subtree of $$$i$$$.
The answer to the problem is $$$dp_1$$$. Complexity is $$$O(n)$$$.
#include <bits/stdc++.h>
using namespace std;
vector<vector<int>> g(300005);
int ch[300005],dp[300005];
void dfs(int p, int q)
{
ch[p]=1,dp[p]=0; int s=0;
for (auto it : g[p]) if (it!=q)
{
dfs(it,p); s+=dp[it];
ch[p]+=ch[it];
}
for (auto it : g[p]) if (it!=q)
{
dp[p]=max(dp[p],s-dp[it]+ch[it]-1);
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int t; cin>>t;
while (t--)
{
int n; cin>>n;
for (int i=1;i<=n;i++) g[i].clear();
for (int i=1;i<n;i++)
{
int u,v; cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
cout<<dp[1]<<"\n";
}
}
[problem:379553F]
Author: n0sk1ll
There are not a lot of useful black squares.
Consider this algorithm: iterate over all squares in the matrix and find the most distant black square.
Let's find out how to do that efficiently. In fact, only 4 (not necessarily distinct) squares will be useful: one square which minimizes $$$i-j$$$, one square which maximizes $$$i-j$$$, one square which minimizes $$$i+j$$$ and one square which maximizes $$$i+j$$$, where $$$(i,j)$$$ denotes the black cell's coordinates. In other words, we would like to find the most distant "border".
Let's look at the example above. The cell we choose to recolour to yellow creates four regions as shown. The most distant border will be fully contained inside one region, hence we should find distance from our yellow cell to any cell on that border, and that is the maximum possible distance.
The complexity is $$$O(n\cdot m)$$$.
#include <bits/stdc++.h>
using namespace std;
char tab[1003][1003];
pair<int,int> a={-1,-1},b={-1,-1},c={-1,-1},d={-1,-1};
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int t; cin>>t;
while (t--)
{
a={-1,-1},b={-1,-1},c={-1,-1},d={-1,-1};
int n,m; cin>>n>>m;
for (int i=0;i<n;i++) cin>>tab[i];
vector<pair<int,int>> interesting;
for (int i=0;i<n;i++) for (int j=0;j<m;j++) if (tab[i][j]=='B')
{
if (a.first==-1 || i+j>a.first+a.second) a={i,j};
if (b.first==-1 || i+j<b.first+b.second) b={i,j};
if (c.first==-1 || i-j>c.first-c.second) c={i,j};
if (d.first==-1 || i-j<d.first-d.second) d={i,j};
}
interesting.push_back(a);
interesting.push_back(b);
interesting.push_back(c);
interesting.push_back(d);
int ans=1e9; pair<int,int> opt;
for (int i=0;i<n;i++) for (int j=0;j<m;j++)
{
int dist=0;
for (auto it : interesting) dist=max(dist,abs(i-it.first)+abs(j-it.second));
if (dist<ans) ans=dist,opt={i,j};
}
cout<<opt.first+1<<" "<<opt.second+1<<"\n";
}
}
[problem:379553D]
Author: wxhtzdy
Increase every $$$0$$$ by $$$1$$$ initially.
Check if the answer is $$$0$$$: check whether the graph is already connected.
Check if the answer is $$$1$$$.
If the answer is not $$$0$$$ or $$$1$$$, then it is $$$2$$$.
Firslty, let's understand how to check whether the graph induced by some array $$$b$$$ is connected in $$$O(n \ log \ max \ b_i)$$$. We create a graph over bits. Let's take all elements $$$b_i$$$ and add an edge between their adjacent bits (all bits of a single $$$b_i$$$ will be connected). To quickly access the lowest bit we will use $$$b_i \ \& \ -b_i$$$ in code. Now we just check whether the graph over bits is connected.
We check whether the graph for initial array $$$a$$$ is connected. If it is, the answer is 0.
Then, we wonder if the answer is $$$1$$$. Check if at least one of the graphs for arrays $$$a_1,...,a_{i-1},a_i-1,a_{i+1},...,a_n$$$ for every $$$1\leq i \leq n$$$ is connected. Do the same for arrays $$$a_1,...,a_{i-1},a_i+1,a_{i+1},...,a_n$$$. If none of the graphs is connected, the answer is $$$2$$$ and otherwise $$$1$$$.
Now let's see how the answer will be at most $$$2$$$. Let $$$i_1,i_2,...,i_k$$$ be the sequence of indices denoting that $$$a_{i_j}$$$ has the highest lowest bit (the highest value of $$$a_i \ \& \ -a_i$$$). if $$$k=1$$$ then we can just decrease $$$a_{i_1}$$$ by $$$1$$$ and connect everything. If $$$k\geq 2$$$ and we do the same we might disconnect that number from other numbers having the highest lowest bit, thus an additional operation of adding $$$1$$$ to $$$a_{i_2}$$$ is needed to keep everything connected. The answer is $$$2$$$ in this case.
Complexity of this solution is $$$O(n^2 \ log \ max \ a_i)$$$.
#include <bits/stdc++.h>
using namespace std;
int a[2005];
vector<vector<int>> g(32);
bool vis[32];
void dfs(int p)
{
if (vis[p]) return; vis[p]=1;
for (auto it : g[p]) dfs(it);
}
bool connected(int n)
{
int m=0;
for (int i=0;i<n;i++) if (a[i]==0) return false;
for (int i=0;i<n;i++) m|=a[i];
for (int i=0;i<31;i++) g[i].clear();
for (int i=0;i<n;i++)
{
int last=-1;
for (int j=0;j<31;j++)
if (a[i]&(1<<j)){
if (last!=-1) g[last].push_back(j),g[j].push_back(last);
last=j;
}
}
for (int j=0;j<31;j++) vis[j]=0;
for (int j=0;j<31;j++) if ((1<<j)&m)
{
dfs(j); break;
}
for (int j=0;j<31;j++) if (((1<<j)&m) && !vis[j]) return false;
return true;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int t; cin>>t;
while (t--){
int n; cin>>n;
for (int i=0;i<n;i++) cin>>a[i];
int ans=0;
for (int i=0;i<n;i++) if (a[i]==0) ans++,a[i]++;
int m=0;
for (int i=0;i<n;i++) m=max(m,(a[i]&(-a[i])));
if (connected(n))
{
cout<<ans<<"\n";
for (int i=0;i<n;i++) cout<<a[i]<<" "; cout<<"\n";
goto kraj;
}
for (int i=0;i<n;i++)
{
a[i]--;
if (connected(n))
{
cout<<ans+1<<"\n";
for (int i=0;i<n;i++) cout<<a[i]<<" "; cout<<"\n";
goto kraj;
}
a[i]++;
}
for (int i=0;i<n;i++)
{
a[i]++;
if (connected(n))
{
cout<<ans+1<<"\n";
for (int i=0;i<n;i++) cout<<a[i]<<" "; cout<<"\n";
goto kraj;
}
a[i]--;
}
for (int i=0;i<n;i++) if ((a[i]&-a[i])==m)
{
a[i]--;
break;
}
for (int i=0;i<n;i++) if ((a[i]&-a[i])==m)
{
a[i]++;
break;
}
cout<<ans+2<<"\n";
for (int i=0;i<n;i++) cout<<a[i]<<" ";
cout<<"\n";
kraj:;
}
}