Codeforces Round #764 (Div. 3)
Codeforces Round #764 (Div. 3)
VP直播回放:https://www.bilibili.com/video/BV1GT4y127WQ (A-D)
A - Plus One on the Subset
讲了一堆,最后只要最大-最小就行了。
/* Author: cyanine_farewell
* Time: 2022-01-19 19:30:03
**/
#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 60;
int main()
{
fast;
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
int x;
int maxx=0;
int minn=1e9;
for(int i=1;i<=n;i++)
{
cin>>x;
maxx=max(maxx,x);
minn=min(minn,x);
}
cout<<maxx-minn<<'\n';
}
return 0;
}
B - Make AP
题意:仅进行一次如下操作:选择\(a,b,c\)中的一个数,让其乘上一个正整数\(m\),最终\(a,b,c\)形成等差数列。
思路:由于是等差数列,所以最终的\(a,b,c\)满足\(a+c=2\cdot b\)。我们分别讨论改变\(a,b,c\)形成等差数列的可行性。如果改变\(a\),我们需要考虑\((2\cdot b-c)%a\)是否为\(0\),同时商是否大于\(0\);改变\(c\)类似。改变\(b\)需要多考虑\((a+c)\)是否能被\(2\)整除。
/* Author: cyanine_farewell
* Time: 2022-01-19 19:30:03
**/
#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 100010;
int main()
{
fast;
int T;
cin>>T;
while(T--)
{
bool flag=0;
int a,b,c;
int ma,mb,mc;
cin>>a>>b>>c;
ma=b-(c-b);
if(ma%a==0 && ma/a>0)
{
cout<<"YES\n";
continue;
}
mc=b+(b-a);
if(mc%c==0 && mc/c>0)
{
cout<<"YES\n";
continue;
}
if((c+a)%2==0)
{
mb=(a+c)/2;
if(mb%b==0 && mb/b>0)
{
cout<<"YES\n";
continue;
}
}
cout<<"NO\n";
}
return 0;
}
C - Division by Two and Permutation
题意:给出\(n\)个数,重复如下操作:选择其中一个数\(x\)进行\(\lfloor x/2 \rfloor\)。问\(n\)个数能否构成\(1-n\)的排列。
思路:例如想要获得数字\(2\),它可以从\(4\)和\(5\)经过操作得来。可以发现较小的数字可以从多个较大的数字经过操作得到。因此,我们先将所有的数的范围控制在\(1-n\),统计各个数的个数\(f[i]\),从大到小遍历,如果\(f[i]>1\),那么就可以把多的数字进行操作,状态转移方程为\(f[i/2]+=f[i]-1\),最后判断\(1-n\)范围内所有的\(f[i]\)是否均为\(1\)。
/* Author: cyanine_farewell
* Time: 2022-01-19 19:30:03
**/
#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 60;
int f[maxn];
int main()
{
fast;
int T;
cin>>T;
while(T--)
{
int x;
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
f[i]=0;
}
for(int i=1;i<=n;i++)
{
cin>>x;
while(x>n) x/=2;
f[x]++;
}
for(int i=n;i>=1;i--)
{
if(f[i]>1)
{
f[i/2]+=f[i]-1;
}
}
bool ans=1;
for(int i=1;i<=n;i++)
{
if(f[i]==0)
{
ans=0;
break;
}
}
if(ans) cout<<"YES\n";
else cout<<"NO\n";
}
return 0;
}
D - Palindromes Coloring
题意:给出一个字符串和\(k\)种颜色,对字符串中的字符涂色(必须\(k\)种颜色全部用到,所有字符不需要都涂上色),使得相同颜色的字符在交换顺序后能够形成回文串,问形成的最小回文串的最大长度。
思路:若想构成回文串,至多一种字符的个数为奇数,其余均为偶数。首先统计每个字符的个数,如果个数为奇数,就将多出来的那一个统计入\(rest\),使得每种字符的统计个数均为偶数,设这些字符个数总数为\(x\),那么可以构成\(k\)个长度为\(x/k\)的回文串与\(x\%k\)个剩余字符。如果\(x/k\)为奇数,那么必然无法加上新的字符,答案即为\(x/k\);如果\(x/k\)为偶数,我们可以对其中的回文串加上新的字符,那么只需要讨论\(x\%k+rest\)与\(k\)的大小关系。如果\(x\%k+rest \geq k\),答案为\(x/k+1\),否则为\(x/k\)。
/* Author: cyanine_farewell
* Time: 2022-01-19 19:30:03
**/
#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 100010;
int n,k;
string s;
int d[26]={0};
int main()
{
fast;
int T;
cin>>T;
while(T--)
{
int rest=0;
int sum=0;
cin>>n>>k;
cin>>s;
for(int i=0;i<26;i++)
{
d[i]=0;
}
for(int i=0;i<n;i++)
{
d[s[i]-97]++;
}
for(int i=0;i<26;i++)
{
rest+=d[i]%2;
d[i]=d[i]/2*2;
sum+=d[i];
}
int ans=sum/k;
int r=sum%k;
if(ans%2)
{
ans=ans;
}
else
{
if(r+rest>=k)
{
ans++;
}
}
cout<<ans<<'\n';
}
return 0;
}
E - Masha-forgetful
题意:给出\(n\)个字符串,给出一种组合方式,使得这\(n\)个字符串的若干个子串可以构成指定的字符串。
思路:因为不需要考虑最少子串,因此我们把所有的字符串拆成长度为\(2\)和\(3\)的子串。然后对于给定的字符串,对于当前位置\(i\),判断包含以位置\(i\)结尾的长度\(2\)和\(3\)的子串是否在\(n\)个字符串中出现过,若出现过则记录前驱。最后根据前驱输出答案。
/* Author: cyanine_farewell
* Time: 2022-01-20 01:16:59
**/
#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 1010;
int n,m;
map<string,bool> vis;
map<string,tuple<int,int,int>> pos;
bool dp[maxn];
int pr[maxn];
int main()
{
fast;
int T;
cin>>T;
while(T--)
{
pos.clear();
vis.clear();
string s;
string t;
cin>>n>>m;
for(int i=0;i<=m;i++)
{
dp[i]=0;
pr[i]=0;
}
dp[0]=1;
for(int i=1;i<=n;i++)
{
cin>>s;
for(int j=0;j<m;j++)
{
t=s[j];
for(int k=1;k<=2;k++)
{
if(k+j>=m) break;
t+=s[j+k];
if(!vis[t])
{
vis[t]=1;
pos[t]=make_tuple(j,j+k,i);
}
}
}
}
cin>>s;
for(int i=0;i<m;i++)
{
t=s[i];
for(int k=1;k<=2;k++)
{
if(i-k<0) break;
t=s[i-k]+t;
if(vis[t] && dp[i-k])
{
dp[i+1]=1;
pr[i+1]=i-k;
}
if(dp[i+1]) break;
}
}
if(!dp[m])
{
cout<<"-1\n";
continue;
}
vector<tuple<int,int,int>> ans;
for(int k=m;k>0;)
{
int p=pr[k];
string t=s.substr(p,k-p);
ans.emplace_back(pos[t]);
k=p;
}
reverse(ans.begin(),ans.end());
cout<<ans.size()<<'\n';
for(auto [l,r,i]:ans)
{
cout<<l+1<<' '<<r+1<<' '<<i<<'\n';
}
}
return 0;
}
F - Interacdive Problem
题意:交互,给出\(n\),猜测\(x(1\leq x < n)\)的值。交互方式为:给出\(c\),\(x=x+c\),返回\(\lfloor \frac{x}{n} \rfloor\)。交互不超过\(10\)次,\(1\leq n \leq 1000\)。
思路:补题的时候感觉题解的思路不太符合自己的常规想法,改了一些小的细节。假定当前余数范围为\([l,r]\),以第一次为例,余数范围为\([1, n-1]\),进行二分余数的操作,取得\(mid\)后给出\(c=n-mid\),如果返回的结果比上一次大,说明余数范围在\([mid,r]\),反之在\([l,mid]\)。同时,由于\(x=x+c\),因此余数范围也发生了变化,需要加上\(c\)并进行取模。可以在对数次数内找到结果,也就是\(10\)次内。
需要注意的是,这个思路在\(l=0,r=1,mid=(l+r)/2\)时会进入死循环,因此将\(mid=(l+r+1)/2\)即可。
最终结果为最后一次返回的结果加上\(l\)(或者\(r\),因为此时\(l==r\))。
/* Author: cyanine_farewell
* Time: 2022-01-19 19:30:03
**/
#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 100010;
int n;
int main()
{
fast;
cin>>n;
int l=1,r=n-1;
int d=0;
int x;
int ans;
while(l<r)
{
int mid=(l+r+1)/2;
cout<<"+ "<<n-mid<<endl;
cin>>x;
if(x>d) l=mid;
else r=mid-1;
l=(l+n-mid)%n;
r=(r+n-mid)%n;
d=x;
}
cout<<"! "<<d*n+l<<endl;
return 0;
}
G - MinOr Tree
题意:给出一张图,问对于或运算的最小生成树的值。
思路:不需要考虑具体留下哪些边。按位从高位进行处理,判断在去掉该位为\(1\)的边后剩余的边能否连通,若能则去掉这些边,不能则保留。连通性利用并查集可以判断。
/* Author: cyanine_farewell
* Time: 2022-01-19 19:30:03
**/
#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 200010;
struct Edge{
int u,v,w;
};
bool vis[maxn];
Edge E[maxn];
int f[maxn];
int n,m;
int Find(int x)
{
if(f[x]==x) return x;
return f[x]=Find(f[x]);
}
void Union(int x,int y)
{
x=Find(x);
y=Find(y);
if(x==y) return;
f[x]=y;
return;
}
bool check(int x)
{
for(int i=1;i<=n;i++)
{
f[i]=i;
}
for(int i=1;i<=m;i++)
{
if(vis[i] || E[i].w&(1<<x)) continue;
int u=E[i].u,v=E[i].v;
Union(u,v);
Union(v,u);
}
for(int i=1;i<=n;i++)
{
if(Find(1)!=Find(i)) return 0;
}
return 1;
}
int main()
{
fast;
int T;
cin>>T;
while(T--)
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
vis[i]=0;
cin>>E[i].u>>E[i].v>>E[i].w;
}
int res=0;
for(int i=30;i>=0;i--)
{
if(check(i))
{
for(int j=1;j<=m;j++)
{
if(E[j].w&(1<<i)) vis[j]=1;
}
}
else res+=(1<<i);
}
cout<<res<<'\n';
}
return 0;
}