Codeforces Round #572 (Div. 2)(题解)
A. Keanu Reeves
题目大意
给出一段01序列,现希望将其分为尽可能少段使得每一段的0和1的数量都不相同
解题思路
分情况,如果原串0和1数量已经不同,则直接输出原串即可,如原串0和1的数量相同,则将原串分为两个串的第一个串为原串的第一个字符,第二个串为原串的剩下
AC代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
char s[105];
scanf("%s",s+1);
int z=0,o=0;
for(int i=1;i<=n;i++)
{
if(s[i]=='0') z++;
else o++;
}
if(o!=z)
{
puts("1");
printf("%s\n",s+1);
}
else
{
printf("2\n");
printf("%c %s",s[1],s+2);
}
}
B. Number Circle
题目大意
给出一些数字,要求将数字狗造成一个环,使得这个环中每个数字的大小都小于这个数两侧的数的和。
解题思路
将给的数字进行排序,再将最大的数和次大的数字交换位置即可得出最容易满足条件的数环,此时只需要满足第三大的数字加上第二大的数字大于最大的数字即可,反之则无解
AC代码
#include<bits/stdc++.h>
using namespace std;
const int size=1e5+5;
int a[size];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+1+n);
swap(a[n],a[n-1]);
if(a[n]+a[n-2]>a[n-1])
{
puts("YES");
for(int i=1;i<=n;i++)
{
printf("%d%c",a[i],i==n?'\n':' ');
}
}
else puts("NO");
}
C. Candies!
题目大意
给出一种操作:
给出一段长度为 2 n ( n ≥ 0 ) 2^n(n\ge0) 2n(n≥0)的序列,现将 a 2 i + 1 , a 2 i + 2 a_{2i+1},a_{2i+2} a2i+1,a2i+2换作 ( a 2 i + 1 + a 2 i + 2 ) m o d 10 (a_{2i+1}+a_{2i+2})mod\ 10 (a2i+1+a2i+2)mod 10,如果 a 2 i + 1 , a 2 i + 2 ≥ 10 a_{2i+1},a_{2i+2}\ge 10 a2i+1,a2i+2≥10则奖励一颗糖果
现在有一序列设为s,则设一函数f(s),其为通过上述操作将原序列长度变为1的过程中最多可以获得多少的糖果。
本题的问题是,给出一段序列。现在有q个询问,每次询问给出一对l和r(保证 r − l + 1 = 2 n r-l+1=2^n r−l+1=2n)问原序列的子序列[l,r]的f函数的函数值为多少
解题思路
对每个位置向后长度为2的次方的倍数预处理出答案即可。每个位置的某个长度的答案可以从这个位置这个长度的一半递推得到。具体见代码
AC代码
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
const int size=1e5+5;
int s[size];
int ans[size][20];
int num[size][20];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&s[i]);
for(int i=1;i<=n;i++) num[i][0]=s[i],ans[i][0]=0;
for(int i=1;i<=int(log2(n));i++)
{
for(int j=1;j+(1<<i)-1<=n;j++)
{
num[j][i]=num[j][i-1]+num[j+(1<<(i-1))][i-1];
ans[j][i]=ans[j][i-1]+ans[j+(1<<(i-1))][i-1];
if(num[j][i]>=10)
{
num[j][i]%=10;
ans[j][i]++;
}
}
}
int q;
scanf("%d",&q);
while(q--)
{
int r,l;
scanf("%d%d",&l,&r);
if(r==l)
{
if(s[l]>=10) puts("1");
else puts("0");
}
else
{
printf("%d\n",ans[l][int(log2(r-l+1+eps))]);
}
}
}
D1. Add on a Tree
题目大意
给出一颗树,现在可以任意选择两个叶子节点,为这两个叶子节点之间的简单路径上的所有的边加上一个或者减去一个任意的实数,现问给出的这棵树可否通过有限次操作使得树上的边的权值达到任意的组合状态。
解题思路
原题的题意即所有的边的权值是否可以最终都变成不同的值。如果想要对任意的边修改权值而不影响到其他边,则这条边就需要被叶子路径经过至少两次,这就要求除了叶子节点以外所有的点的度都要大于等于3
AC代码
#include<bits/stdc++.h>
using namespace std;
const int size=1e5+5;
int du[size];
int main()
{
int n;
scanf("%d",&n);
memset(du,0,sizeof(du));
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
du[u]++,du[v]++;
}
if(n==2)
{
puts("YES");
}
else
{
for(int i=1;i<=n;i++)
{
if(du[i]<=2&&du[i]!=1)
{
puts("NO");
return 0;
}
}
puts("YES");
}
}
D2. Add on a Tree: Revolution
题目大意
和上题相似,不同的是现在给出一棵树,以及目标得到的权值(所有的权值都是互不相同且为偶数的)。问可否通过上面给出的操作得到这种树
解题思路
根据上题可知,如果想到所有的边可以叨叨互不相同的值则需要满足除了叶子节点所有的节点的度数都大于等于3,则对于一条边而言(先假设其两端的节点都不是叶子节点),则两个端点向着非另一个端点的方向至少有两个叶子节点,设两个端点分别在左右,则左节点向左的叶子节点中选出两个设为A,B,右节点向右的叶子节点中选出两个设为C,D,则只要AD=val/2,BC=val/2,AB=-val/2,CD=-val/2即可,如有一个端点为叶子节点,(假设为左节点)则使得A,B都为这个叶子节点,且A,B之间不再进行操作
AC代码
#include<bits/stdc++.h>
using namespace std;
const int size=1005;
struct Edge{
int u,v,w;
Edge(){}
Edge(int u,int v,int w):u(u),v(v),w(w){}
};
vector<Edge> e;
vector<int> G[size];
vector<int> x,y;
vector<Edge> ans;
int a,b,c,d;
void dfs(int v,int f,int mode)
{
if(G[v].size()==1)
{
if(mode==0)
{
if(a==0) a=v;
b=v;
}
if(mode==1)
{
if(c==0) c=v;
d=v;
}
}
for(auto u:G[v])
{
if(u==f) continue;
dfs(u,v,mode);
}
}
int main()
{
int n,u,v,w;
scanf("%d",&n);
for(int i=1;i<=n-1;i++)
{
scanf("%d%d%d",&u,&v,&w);
e.push_back(Edge(u,v,w));
G[u].push_back(v);
G[v].push_back(u);
}
for(int i=1;i<=n;i++)
{
if(G[i].size()!=1&&G[i].size()<3)
{
puts("NO");
return 0;
}
}
puts("YES");
for(auto ed:e)
{
u=ed.u,v=ed.v,w=ed.w;
a=b=c=d=0;
dfs(u,v,0);
dfs(v,u,1);
ans.push_back(Edge(a,c,w/2));
ans.push_back(Edge(b,d,w/2));
if(a!=b) ans.push_back(Edge(a,b,-w/2));
if(c!=d) ans.push_back(Edge(c,d,-w/2));
}
printf("%d\n",ans.size());
for(auto e:ans)
{
printf("%d %d %d\n",e.u,e.v,e.w);
}
}
E. Count Pairs
题目大意
给出一个素数p,n个整数
a
1
,
a
2
,
a
3
,
a
4
,
.
.
.
a
n
a_1,a_2,a_3,a_4,...a_n
a1,a2,a3,a4,...an,和一个整数k。
问有多少组(i,j)(
1
≤
i
<
j
≤
n
1\le i<j\le n
1≤i<j≤n)满足
(
a
i
+
a
j
)
(
a
i
2
+
a
j
2
)
≡
k
(
m
o
d
p
)
(a_i+a_j)(a_i^2+a_j^2)\equiv k(mod\ p)
(ai+aj)(ai2+aj2)≡k(mod p)
解题思路
( a i + a j ) ( a i 2 + a j 2 ) ≡ k ( m o d p ) ( a i − a j ) ( a i + a j ) ( a i 2 + a j 2 ) ≡ ( a i − a j ) ∗ k ( m o d p ) a i 4 − a j 4 ≡ a i k − a j k ( m o d p ) a i 4 − a i k ≡ a j 4 − a j k ( m o d p ) (a_i+a_j)(a_i^2+a_j^2)\equiv k(mod\ p)\\ (a_i-a_j)(a_i+a_j)(a_i^2+a_j^2)\equiv (a_i-a_j)*k(mod\ p)\\ a_i^4-a_j^4\equiv a_ik-a_jk(mod\ p)\\ a_i^4-a_ik\equiv a_j^4-a_jk(mod\ p) (ai+aj)(ai2+aj2)≡k(mod p)(ai−aj)(ai+aj)(ai2+aj2)≡(ai−aj)∗k(mod p)ai4−aj4≡aik−ajk(mod p)ai4−aik≡aj4−ajk(mod p)
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
unordered_map<int,int> mp;
int main()
{
int n,p,k;
scanf("%d%d%d",&n,&p,&k);
LL a;
mp.clear();
long long ans=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a);
int val=(a*a%p*a%p*a%p-a*k%p+p)%p;
ans+=(mp[val]++);
}
printf("%lld\n",ans);
}