一。A.フェニックスとバランス
1.効果:
2から2 ^ nまでのn個の数があります。それらをランダムに2つの山に分割し(各山はn / 2)、nが偶数であることを確認して、n /の2つの山の合計の差を求めます。 2つの数字が最小です
2.問題解決:
ルールを探すと、1つの山に分かれていることがわかりました:2 n / 2、2 n / 2 + 1、...、2 n-1、(合計n / 2の数)、
もう1つの山は・:2 1、2 2、... 2 N / 2-1、2 Nで
、この場合、両者の差が最小である。
式である:2 N / 2 + 1 -2
用途は満たすためにPOW T、高速電力を使用他の人の方法を読んだ後、それは前の数* 2 + 2でもあり得ることがわかりました、本質はほとんど同じです
3.acコード:
#include<stdio.h>
#include<bits/stdc++.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
//long long int dp2[400000],dp1[400000],a[400000];
using namespace std;
typedef long long ll;
ll quick_pow(ll a,ll b) {
ll ans = 1;
while(b) {
if(b&1)
ans *= a;
a *= a;
b >>= 1;
}
return ans;
}
int main(){
int t;
int n,i;
long long int a[40];
for(i=2;i<=32;i+=2){
a[i]=quick_pow(2,i/2+1)-2;
}
while(cin>>t){
while(t--){
cin>>n;
cout<<a[n]<<endl;
}
}
}
二。G.奇数の選択
1.効果:
n個の数の配列があります。n個の数からx個の数を選択し、それらの合計を奇数にします。はいの場合、はい、いいえいいえ
2.問題解決:
まず、絶対に不可能ないくつかの特殊なケースを除外し
ます。1。すべて偶数
2.すべて奇数、ただしxは偶数
3. n == xの
場合、合計が偶数/奇数である残りのケースは偶数です。問題はx <nであることが保証されています。常に最初に偶数を見つけ、偶数に応じて奇数を調整し、最終結果を奇数にすることができます。
3.acコード:
#include<stdio.h>
#include<bits/stdc++.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
//long long int dp2[400000],dp1[400000],a[400000];
using namespace std;
typedef long long ll;
int main(){
int n;
int t;
int x;
int odd,even;
int a[1001];
while(cin>>t){
while(t--){
odd=0;
even=0;
cin>>n>>x;
for(int i=0;i<n;i++){
cin>>a[i];
if(a[i]%2==0)
even++;
else
odd++;
}
if(n==even)
printf("No\n");
else if(n==odd && x%2==0)
printf("No\n");
else if(n==x&&odd%2==0)
printf("No\n");
else
printf("Yes\n");
}
}
}
三。H.サブシーケンスの憎悪
1.効果:
文字列sには0/1しかありません。文字列のサブシーケンスに「010」/「101」がある場合、文字列は適切ではありません。文字列内の特定の位置の数を調整して、0-を設定できます。 > 1 / 1-> 0、この文字列を適切にするために、少なくともいくつ変更するかを尋ねます。すべてを変更できます。
2.問題解決:
明らかに、それは最終的に実現する必要があります。左側のすべての1と右側のすべての0、または左側のすべての0と右側のすべての1は
dpと見なされます。2つのdp、1つは必要な数を記録しますi番目の位置で変更され、左側に1、右側に0、その他のレコード別のケースでは、最小のものを見つけて
sum0を使用してすべての0を記録し、sum1はすべての1を記録します。x0
は次の位置を記録します。前の0、x1はです。。1、
左と右の1 0の場合、変更するのが適切です:x0 + sum1-x1
左1と右の0の場合、変更するのが適切です:x1 + sum0-x0
最小値を見つけます
3.acコード:
#include<stdio.h>
#include<bits/stdc++.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
//long long int dp2[400000],dp1[400000],a[400000];
using namespace std;
typedef long long ll;
int main(){
int t,n,i,j;
char s[2000];
while(cin>>t){
while(t--){
scanf("%s",s);
n=strlen(s);
int sum0=0,sum1=0;
int x0=0,x1=0;
for(i=0;i<n;i++){
if(s[i]=='0')
sum0++;
else
sum1++;
}
int out=2000;
for(i=0;i<n;i++){
if(s[i]=='0')
x0++;
else
x1++;
out=min(out,min(x1+sum0-x0,x0+sum1-x1));
}
cout<<out<<endl;
}
}
}
四。B.フェニックスとビューティー
1.効果:
n個の数値が与えられた場合、その中の任意の位置に任意の数値を追加して、配列内のm個の連続する数値の合計を同じにすることができます。可能であれば、配列番号の数を出力し、そうでない場合は、-1を出力します。
2.問題解決:
n個の数の中にm個以上の異なる数がある場合、それは不可能です.m = 3とすると、配列はa、b、c、d、a、b、c、dであり、a + b + cになります。 = b + c + d
n個の数がm個ある場合は、m個をn回コピーします。n個がm個
未満の場合は、m個に加算し、m個をn回繰り返します。
3.acコード:
#include<stdio.h>
#include<bits/stdc++.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#define N 300010
using namespace std;
typedef long long ll;
int a[N],b[N];
set<int> s;
int main(){
int t,n,k;
int i,j;
while(cin>>t){
while(t--){
s.clear();
cin>>n>>k;
memset(b,0,sizeof(b));
memset(a,0,sizeof(a));
for(i=0;i<n;i++){
cin>>a[i];
s.insert(a[i]);
}
int n1=s.size();
if(n1>k){
printf("-1\n");
continue;
}
j=1;
while(s.size()<k){
s.insert(j);
j++;
}
set<int>::iterator iter;
int x=0;
for(iter=s.begin();iter!=s.end();iter++){
b[x++]=*iter;
}
printf("%d\n",n*x);
for(i=0;i<n-1;i++){
for(j=0;j<x;j++){
printf("%d ",b[j]);
}
}
for(j=0;j<x-1;j++){
printf("%d ",b[j]);
}
printf("%d\n",b[j]);
}
}
}
五。I.葉のゲーム
1.効果:
n個のノードを持つ根なしツリーを考えると、2人が交代で取り、リーフノードを取り、彼に接続されているエッジを削除できるたびに、xを取得した人、勝った人を削除します。
2.問題解決:
ゲームでは、誰もが最適な
ノードを選択します。注:xが最初にリーフノードであり、ツリーにノードが1つしかない
場合、残りのケース> = 2の場合、最初の手がxに接続されたエッジを獲得します。どちらも最善の解決策です。この場合、最終的には次の図になります。
このとき、最初の動きは無効になります。
どちらもサブツリーを完成させたくないので、そうでなければxは葉になります。したがって、2人は間違いなく2つのサブツリーを残し、他に取得する方法がなくなるまでxを葉に変えます。したがって、これは上記の場合です。そうすれば、nのパリティを判断するだけで誰が勝つかを判断できます。
3.acコード:
#include<stdio.h>
#include<bits/stdc++.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#define N 300010
using namespace std;
typedef long long ll;
int a[N],b[N];
int main(){
int t;
int x,n;
int u,v;
int i;
while(cin>>t){
while(t--){
memset(a,0,sizeof(a));
cin>>n>>x;
for(i=0;i<n-1;i++){
cin>>u>>v;
a[u]++;
a[v]++;
}
if(a[x]<=1||n%2==0){
printf("Ayush\n");
}else{
printf("Ashish\n");
}
}
}
}
六。C.フェニックスと流通
1.効果:
長さnの文字列を指定し、それをk個の部分に分割し、
辞書式順序が最大になるサブシーケンスが最小になるように順序を調整します。辞書式サイズ:a <b、ab <abb、abc <ac ...
この質問つまり、これは、最大の辞書式順序を持つk個のサブ文字列の1つが存在する必要があるため、最大の辞書式順序は可能な限り小さくなります。
2.問題解決:
参照
最初に文字列を並べ替え、これに従って分割し
ます。最大と最小が必要な場合は、最初のkと最後のnkの組み合わせである必要があります。辞書式順序は
、最初のkかどうかを判断するために可能な限り小さくなります。文字は同じです。異なる場合は、最初のs [k]が配置されている文字列は、辞書式順序で最大である必要があります。最小にする方法は、文字列にs [k]のみがあり、残りのnkがあることです。文字は、abbb | ccccなどのs [k]未満の文字に割り当てられ、accc、b、b、bに分割されます。
前の文字が同じである
場合は、次のnk文字が同じであるかどうかを判断します。同じ、aaa | bbbbのように、後者のnk文字は均等に分散さ
れます。aaa| bbcのように違いがある場合、nkの異なる文字は大小でなければならないため、後者はaに割り当てられます。分離されると、後ろの大きなものが前に走って大きくなります。辞書式順序で並べると最小になります。ac> abbcなど
3.acコード:
#include<stdio.h>
#include<bits/stdc++.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#define N 300010
using namespace std;
typedef long long ll;
char s[N];
int main(){
int t;
int n,k;
int i;
while(cin>>t){
while(t--){
cin>>n>>k;
scanf("%s",s);
sort(s,s+n);
int flag=0;
for(i=1;i<k;i++){
if(s[i]!=s[i-1])
flag=-1;
}
if(flag==-1){
printf("%c\n",s[k-1]);
}else{
for(i=k+1;i<n;i++){
if(s[i]!=s[i-1])
flag=-1;
}
if(flag==-1){
printf("%c",s[k-1]);
for(i=k;i<n;i++){
printf("%c",s[i]);
}
printf("\n");
}else{
int x=(n-k)/k;
printf("%c",s[k-1]);
for(i=k;i<k+x;i++){
printf("%c",s[i]);
}
if((n-k)%k!=0)
printf("%c",s[k]);
printf("\n");
}
}
}
}
}