A-Divisibility Problem
水
B-K-th Beautiful String
写的时候居然超时,哥们惊了,应该字符串用string的加法然后用cout<<string造成的,水题
C-Ternary XOR
从高位往低位看,如果当前位置是0,那么0=0+0
如果当前位置是2,那么当前位置是1+1=2,如果当前位置是1,那么让第一个数为1,另外一个数这一位为0,这样第一个数一定大于另外一个,后面的操作就是让第二数尽可能的大。
D-Carousel CodeForces
题意:一个环,环上编号从1-n,并且n和1相邻,每个位置会有一种动物,这个动物类型是ti,ti相同的表示为一种动物。要求对环染色,相邻的动物如果不同类型,那么颜色也应该不同,输出一种染色方法。
思路:如果是偶数的环,那么直接1-2-1-2就可以,如果是奇数的环,那么很简单,找到两个相同类型的动物,作为头和尾,染1-2-1-2,虽然最后出现1-1但是因为动物类型相同就可以,如果找不到就把最后用3代替。
代码:
#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
using namespace std;
const int maxx = 2e5+6;
int a[maxx];
int main(){
int t,n;
#ifdef ONLINE_JUDGE
#else
freopen("in.txt","r",stdin);
#endif
scanf("%d",&t);
while(t--){
scanf("%d",&n);
int minn=2e5+6;
int maxx=0;
for (int i=0;i<n;i++){
scanf("%d",&a[i]);
minn=min(minn,a[i]);
maxx=max(maxx,a[i]);
}
if (minn==maxx){
printf("1\n");
for (int i=1;i<=n;i++){
printf("1 ");
}
printf("\n");
continue;
}
if (n%2==0){
printf("2\n");
int flag=0;
for (int i=0;i<n;i++){
printf("%d ",flag+1);
flag=flag^1;
}
printf("\n");
}else{
int pos=-1;
for (int i=0;i<n;i++){
//cout<<a[i]<<"-"<<a[(i+1)%n]<<endl;
if(a[i]==a[(i+1)%n]){
pos=i+1;
break;
}
}
if (pos==-1){
int flag=1;
printf("3\n");
for (int i=0;i<n-1;i++){
printf("%d ",flag+1);
flag=flag^1;
}
printf("3 ");
printf("\n");
}else {
int flag=0;
printf("2\n");
for (int i=0;i<n;i++){
if (i==pos){
flag=flag^1;
}
printf("%d ",flag+1);
flag=flag^1;
}
printf("\n");
}
}
}
return 0;
}
E-Tree Queries
题意: 对于一棵树,是否能够找到从根到某个点的一条路径,使得询问的点和这条路的距离不超过1。
思路:我们可以通过BFS算出每个点的深度,然后在询问对时候,对这些点按照深度排序,我们检查相邻深度的点,是否满足相邻节点的LCA距离均大于1,如果满足就代表找不到,因为就出现了两个分叉深度均大于等于2的情况,不满足题意。
易错点: 写排序的时候注意加cmp函数
代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<queue>
using namespace std;
const int SIZE = 2e5+6;
int f[SIZE][30],d[SIZE];
int ver[2*SIZE],Next[2*SIZE],edge[2*SIZE],head[SIZE];
int T,n,m,tot,t;
queue<int>q;
int a[SIZE];
bool cmp(int x,int y){
return d[x]<d[y];
}
void add(int x,int y){
ver[++tot]=y;Next[tot]=head[x];head[x]=tot;
ver[++tot]=x;Next[tot]=head[y];head[y]=tot;
}
void bfs(){
q.push(1);
d[1]=1;
while(q.size()){
int x=q.front();
q.pop();
for (int i=head[x];i;i=Next[i]){
int y=ver[i];
if (d[y])continue;
d[y]=d[x]+1;
f[y][0]=x;
//由于是bfs,那么y点上面深度的点一定全部存在了
for (int j=1;j<=t;j++)
f[y][j]=f[f[y][j-1]][j-1];
//这相当于(2^j-1)+(2^j-1)=2^j
q.push(y);
}
}
}
int lca(int x,int y){
if (d[x]>d[y])swap(x,y); //保证y深度大
//把y深度从大往小找,类似与往上走的每次按照2的倍数去试,可以就往上,路径就是类似用二进制表示
//一定能保证y跳到和x一样的深度
for (int i=t;i>=0;i--)
if (d[f[y][i]]>=d[x])y=f[y][i];
if (x==y)return x;
//然后像上面一样一起跳
for (int i=t;i>=0;i--)
if (f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
//上面保证了f[x][i]!=f[y][i]
//查到最后,一定就是父亲节点刚好是f[x][0]=f[y][0]
return f[x][0];
}
int main(){
int n,m;
int uu,vv;
#ifdef ONLINE_JUDGE
#else
freopen("in.txt","r",stdin);
#endif
while(~scanf("%d%d",&n,&m)){
t=(int)(log(n)/log(2))+1;
for (int i=1;i<=n-1;i++){
scanf("%d%d",&uu,&vv);
add(uu,vv);
}
bfs();
while(m--){
int num;
scanf("%d",&num);
int maxn=0;
int p;
for (int i=1;i<=num;i++){
scanf("%d",&a[i]);
if(d[a[i]]>maxn)
{
maxn=d[a[i]];
p=a[i];
}
}
int flag=0;
for (int i=1;i<=num;i++){
int lc=lca(a[i],p);
if (lc!=a[i] && lc!=f[a[i]][0]){
flag=1;
break;
}
}
if (flag){
printf("NO\n");
}else {
printf("YES\n");
}
}
}
return 0;
}
F-Make k Equal
题意:给你1-n数字,你只能进行以下两个操作,1是把数组中最小的数字+1,2是把数组中最大是数组-1,问最少操作多少次使得数组中有k相同的数
思路:数学+前缀和
首先我们把所有数字排序,当把数组中第i个数作为出现k次的数
pre[i]前缀和,bac[i]后缀和
1首先考虑k个数全部是通过小的加上来
1.1当i<k: ia[i]-pre[i]代表把前i个数变到a[i]
1.2当i>jk: ia[i]-pre[i]-(k-i)代表把前i个数变成k个a[i]
那么1.2显然可以作为答案的一种
2 考虑k个数全部是从大的减小过来
2.1 当n-i+1<k:bac[i]-(n-i+1)*a[i]代表把后i个数变到a[i]
2.2 当n-i+1>=k:bac[i]-(n-i+1)*a[i]-(n-k+1-i)代表把后k个数变成a[i]
显然2.2也是答案的一种
考虑答案是通过1+2组合而成的,那么1+2显然是把n个数字移动到a[i]所需的操作数目,但是我们只需要k个,所以把1和2的答案加起来再减去(n-k)即可
三个答案取最小值即可
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<queue>
#define LL long long
using namespace std;
const int maxx = 2e5+6;
LL a[maxx];
LL pre[maxx];
LL bac[maxx];
int main()
{
int k,n;
#ifdef ONLINE_JUDGE
#else
freopen("in.txt","r",stdin);
#endif
while(~scanf("%d%d",&n,&k)){
for (int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
sort(a+1,a+1+n);
pre[0]=0;
for (int i=1;i<=n;i++){
pre[i]=pre[i-1]+a[i];
}
bac[n+1]=0;
for (int i=n;i>=1;i--){
bac[i]=bac[i+1]+a[i];
}
LL ans=1e18;
int max_cnt=0;
int cnt=1;
for (int i=1;i<=n;i++){
if (i!=1 && a[i]==a[i-1]){
cnt++;
}else {
cnt=1;
}
max_cnt=max(max_cnt,cnt);
}
if (max_cnt>=k){
printf("0\n");
continue;
}
for (LL i=1;i<=n;i++){
LL l=i*a[i]-pre[i];
LL r=bac[i]-(n-i+1)*a[i];
//cout<<l<<"-"<<r<<endl;
if (i>=k){
ans=min(ans,l-(i-k));
}
if (n-i+1>=k){
ans=min(ans,r-(n-i+1-k));
}
ans=min(ans,l+r-(n-k));
}
printf("%lld\n",ans);
}
return 0;
}