A. Candies
等比数列求和之后得到k和x的式子,枚举k即可,因为是幂函数,k并不会很大
代码
#include <iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
#include<stdio.h>
#define INF 0x3f3f3f3f
typedef long long int ll;
using namespace std;
inline void read(int &p)
{
p=0;int flag=1;char c=getchar();
while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int q;
read(q);
while(q--){
int n;
cin>>n;
ll k,ans;
for(k=2;;k++){
ll cnt=(1<<k)-1;
if(n%cnt==0){
ans=n/cnt;break;
}
}
cout<<ans<<endl;
}
return 0;
}
B. Balanced Array
只要n能整除4即可
我的构造是偶数部分都输出2i,奇数部分前一半输出2i-1,后一半输出2i+1
代码
#include <iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
#include<stdio.h>
#define INF 0x3f3f3f3f
typedef long long int ll;
using namespace std;
inline void read(int &p)
{
p=0;int flag=1;char c=getchar();
while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int q;
cin>>q;
while(q--){
int n;
cin>>n;
n/=2;
if(n%2){
printf("NO\n");
}
else{
printf("YES\n");
for(int i=1;i<=n;i++) cout<<2*i<<" ";
for(int i=1;i<=n;i++){
if(i<=n/2) cout<<2*i-1<<" ";
else cout<<2*i+1<<" ";
}
cout<<"\n";
}
}
return 0;
}
C. Alternating Subsequence
题意相当于给的数列是负数数列和正数数列交替,要从每个负数部分和每个正数部分都选出一个数,来构造一个新的数列,让这个数列的和最大。这样只需要在每个部分都选最大的那个数就好了
代码
#include <iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
#include<stdio.h>
#define INF 0x3f3f3f3f
typedef long long int ll;
using namespace std;
inline void read(int &p)
{
p=0;int flag=1;char c=getchar();
while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int q;
cin>>q;
while(q--){
int n;
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++) {cin>>a[i];}
ll ans=0;
ll pre=a[1],now=1234567890;
for(int i=1;i<=n;i++){
now=a[i];
if(pre>0&&now>0){
now=max(pre,now);
pre=now;
}
else if(pre<0&&now<0){
now=max(pre,now);
pre=now;
}
else{
ans+=pre;
pre=now;
}
}
ans+=pre;
cout<<ans<<endl;
}
return 0;
}
D. Constant Palindrome Sum
对于每一对数,和他们的和sum,我们可以用cnt数组存储sum出现的次数,还可以知道这对数只改变一个元素所能得到的sum的范围,用一个差分数组pref来存储这个范围的上下界,统计完所有数后,差分数组求前缀和就能知道对于某个x,有多少组数可以操作不超过1次得到x。枚举所有可能的x,对应的答案就是操作不超过1次能得到x的对数减去和已经是x的对数,再加上2乘以操作两次才能得到x的对数。其中总对数减去操作不超过1次能得到x的对数就是操作两次才能得到x的对数。
代码
#include <iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
#include<stdio.h>
#define INF 0x3f3f3f3f
typedef long long int ll;
using namespace std;
inline void read(int &p)
{
p=0;int flag=1;char c=getchar();
while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
vector<int> a;
map<int,int> cnt,pref;
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int q;
read(q);
while(q--){
int n,k;
cin>>n>>k;
a.resize(n);
cnt.clear(),pref.clear();
for(auto &x:a) read(x);
for(int i=0;i<n/2;i++) cnt[a[i]+a[n-i-1]]++;
for(int i=0;i<n/2;i++){
int l=a[i],r=a[n-i-1];
pref[max(l,r)+k+1]--;
pref[min(l,r)+1]++;
}
for(int i=2;i<=2*k;i++){
pref[i]+=pref[i-1];
}
int ans=99999999;
for(int i=2;i<=2*k;i++){
ans=min(ans,pref[i]-cnt[i]+2*(n/2-pref[i]));
}
cout<<ans<<"\n";
}
return 0;
}
E. Weights Distributing
先分别用bfs预处理abc为起点的最短路(每条路长度视为1,要走的路的数量),并把路的花费从小到大排序。寻找一个中介点x,使要走的路变成a——x——b——x——c,这个x也可以是b,统计出每个x对应的要走的最少的路的数量,如果a到x要走m条路,x到b要走n条路,x到c要走q条路,那么可以让n对应前n小的花费(因为要走两遍),剩下的m+p条路对应前n+1到m+p小的花费,就可以得到对应的最小花费。遍历x更新最小值即可。
代码
#include <iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
#include<stdio.h>
#define INF 0x3f3f3f3f
typedef long long int ll;
using namespace std;
inline void read(int &p)
{
p=0;int flag=1;char c=getchar();
while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
vector<vector<int> > mp;
void bfs(int a,vector<int> & d){
queue<int> q;
q.push(a);
d[a]=0;
while(!q.empty()){
int x=q.front();
q.pop();
for(auto i:mp[x]){
if(d[i]!=INF) continue;
d[i]=d[x]+1;
q.push(i);
}
}
}
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int q;
read(q);
while(q--){
int n,m,a,b,c;
cin>>n>>m>>a>>b>>c;
vector<int> p(m);
for(auto &x:p) read(x);
sort(p.begin(),p.end());
mp=vector<vector<int> >(n);
for(int i=0;i<m;i++){
int x,y;
read(x),read(y);
x--;y--;
mp[x].push_back(y);
mp[y].push_back(x);
}
a--;b--;c--;
vector<int> aa(n,INF),bb(n,INF),cc(n,INF);
bfs(a,aa);
bfs(b,bb);
bfs(c,cc);
vector<ll> d(m+1);
for(int i=1;i<=m;i++) d[i]=d[i-1]+p[i-1];
ll ans=1e18;
for(int i=0;i<n;i++){
if(aa[i]+bb[i]+cc[i]>m) continue;
ans=min(ans,d[aa[i]+bb[i]+cc[i]]+d[bb[i]]);
}
cout<<ans<<"\n";
}
return 0;
}
F. Restore the Permutation by Sorted Segments
输入中给出了所有2到n个元素为r的不定长度片段。枚举数组中第一个数,假设为fst,所有含有fst到片段中都删去fst,那么以第二个元素为r的片段中就会剩下一个元素,即a[2],再把所有含a[2]的片段都删去a[2],就能得到a[3],重复这样的操作就能得到所有的元素。求出来一个可能符合的数组后要检验一下是否满足输入所给的n-1个片段。这些片段用set维护较为方便。
代码
#include <iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
#include<stdio.h>
#define INF 0x3f3f3f3f
typedef long long int ll;
using namespace std;
inline void read(int &p)
{
p=0;int flag=1;char c=getchar();
while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int q;
read(q);
while(q--){
int n;
read(n);
vector<set<int> > segs;
for(int i=0;i<n-1;i++){
int k;
read(k);
set<int> seg;
for(int i=0;i<k;i++){
int x;
read(x);
seg.insert(x);
}
segs.push_back(seg);
}
for(int fst=1;fst<=n;fst++){
bool flag=true;
vector<int> ans;
vector<set<int> > cur=segs;
for(auto & x:cur){
if(x.count(fst)){
x.erase(fst);
}
}
ans.push_back(fst);
for(int i=1;i<n;i++){
int num=0;
int nxt=-1;
for(auto &x:cur){
if(x.size()==1){
++num;
nxt=*x.begin();
}
}
if(num!=1){
flag=false;
break;
}
for(auto & x:cur){
if(x.count(nxt)){
x.erase(nxt);
}
}
ans.push_back(nxt);
}
//check
if(flag){
set<set<int> > all(segs.begin(),segs.end());
for(int i=1;i<n;i++){
set<int> seg;
seg.insert(ans[i]);
bool ok=false;
for(int j=i-1;j>=0;j--){
seg.insert(ans[j]);
if(all.count(seg)){
ok=true;
break;
}
}
if(!ok){
flag=false;
break;
}
}
}
if(flag){
for(auto x:ans){
cout<<x<<" ";
}putchar('\n');
break;
}
}
}
return 0;
}