A 选择前n/2 - 1个最小的和一个最大的。
ps:2^31爆有符号int,位运算的优先级很小。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int,int>;
const int N=200010;
int t,n,m;
ll ans;
int main()
{
cin>>t;
while(t--)
{
cin>>n;
ll res=0;
for(int i=1;i<n/2;i++)
res+=(1<<i);
res+=(1<<n);
cout<<abs(((1ll<<(n+1)))-2-res*2)<<endl;;
}
return 0;
}
B 如果数组是循环节长度为k的循环数组就满足题意,如果原数组不同字符的数量大于k那么就不可能完成,否则就一定可以完成。不同字符的数量小于k时再补成k个字符(可以不同也可以相同)就可以作为一个循环节了,循环次数就是n,总共有n*k<=1e4个字符。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int,int>;
const int N=2010;
int t,n,m,k;
int a[N];
bool st[N];
int main()
{
cin>>t;
while(t--)
{
vector<int> num,ans;
cin>>n>>k;
memset(st,0,sizeof st);
for(int i=0;i<n;i++) cin>>a[i],num.push_back(a[i]),st[a[i]]=1;
sort(num.begin(),num.end());
num.erase(unique(num.begin(),num.end()),num.end());
if(num.size()>k) puts("-1");
else
{
for(int i=1;i<=n;i++)
{
if(num.size()==k) break;
if(!st[i]) num.push_back(i);//补成k个不同字符
}
cout<<num.size()*n<<endl;
for(int i=1;i<=n;i++)
for(int j=0;j<num.size();j++)
cout<<num[j]<<' ';
cout<<endl;
}
}
return 0;
}
补:
C 如果最小的字符数量小于k,直接输出第k小的字符就可以。
如果大于等于k,那么可以在每个字符串都放一个最小的字符,这个时候就是把剩余的字符分成k份(可以有空串):如果剩余字符完全相同就均分成k就可以了,否则就是按从小到大的顺序的全部,最后再加上最小的那个字符就可以了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int,int>;
const int N=2010;
int t,n,m,k;
int main()
{
cin>>t;
while(t--)
{
string s;
cin>>n>>k;
cin>>s;
sort(s.begin(),s.end());
if(s[0]!=s[k-1]) cout<<s[k-1];
else
{
cout<<s[0];
if(s[k]==s[n-1])
for(int i=k;i<n;i+=k) cout<<s[k];
else
for(int i=k;i<n;i++) cout<<s[i];
}
cout<<endl;
}
return 0;
}
D 首先应该明确一个思路:每天晚上增加的总重量与每个细胞的中重量没关系而是与细胞的数量有关,每晚增加的总重量就等于细胞的数量。
初始重量是1,最终重量是n,中间需要增加n-1的重量。
第一天有1细胞,可以分裂1个,晚上重量就最多增加2,
第二天最多可以有2个细胞,最多分裂2个细胞,晚上最多增加4
…
这样可以得出来,前i天最多可以增加多少重量:(1<<(i+1))-2
先找到第一个大于等于n-1天数就是答案中的天数num,然后就是确定最终分裂顺序:我是想每天尽量多分裂细胞但总数不能超过n-1,如果第i有了res个细胞(那么总重量在后面num-i+1天每天最少增加res),二分出今天可以分裂的最大细胞数量l,今天分裂 l 个,今晚上就会增加res+ l 的重量,一直将num天填完就行了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int,int>;
const int N=200010;
int t,n,m;
ll ans;
int main()
{
cin>>t;
while(t--)
{
cin>>n;
n--;
vector<int> ve;
int num=1,res=1;
for(int i=2;i;i++)
if(n<=((1ll<<i)-2))
{
num=i-1;
break;
}
for(int i=1;i<=num;i++)
{
int l=0,r=res+1;//二分出来最小的不满足的数量l,那么l-1就是要找的了,这天最多分裂res个,随意r等于res+1就不用特判了
while(l<r)
{
int mid =l+r>>1;
if((mid+res)*(num-i+1)>n) r=mid;
else l=mid+1;
}
/*int l=0,r=res;
if((num-i+1)*res*2<=n)
{
ve.push_back(res);
res+=res;
n-=res;
continue;
}
while(l<r)
{
//cout<<l<<' '<<r<<endl;
int mid =l+r>>1;
if((mid+res)*(num-i+1)>n) r=mid;
else l=mid+1;
}*/ //这和上面这一部分是一样的,多加一个特判。
res+=l-1;
n-=res;
ve.push_back(l-1);
}
cout<<num<<endl;
for(int i=0;i<ve.size();i++)
cout<<ve[i]<<' ';
cout<<endl;
}
return 0;
}