A. Turtle Puzzle: Rearrange and Negate
对数组求和,负数当正数来用,输出和。
#include <bits/stdc++.h>
//#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define fr first
#define se second
#define endl '\n'
using namespace std;int n,ans,tmp;void solve(){cin>>n;per(i,1,n){cin>>tmp;ans+=tmp>0?tmp:-tmp;}cout<<ans<<endl;
}void init(){ans=0;
}
signed main(){ios::sync_with_stdio(false),cin.tie(nullptr);int t;cin>>t;while(t--)solve(),init();return 0;
}
B. Turtle Math: Fast Three Task
你可以进行下列两个操作无限次。
1、选择一个数,删掉他,数组总长度-1(没数的时候不能用)
2、选择一个数,加1
问最少多少次操作,可以让数组的和是3的倍数(或者是0,有特殊情况)
先正常的求和,对3取模之后会有三种情况:0,1,2。
如果是0:那么不需要操作就可以得到答案,输出0。
如果是1:最少需要2步,即让某个数加两次1。考虑能不能有更优解,即1步。找到一个数,对3余数为1,存在的话就只需要1步。
如果是2:最少需要1步,操作1和操作2不用想了,反正都是1步。输出1就行
#include <bits/stdc++.h>
#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define fr first
#define se second
#define endl '\n'
using namespace std;
const int N=1e5+5;int n,a[N],sum;void solve(){cin>>n;per(i,1,n)cin>>a[i],sum+=a[i];int leave=sum%3;if(leave==0){cout<<0<<endl;}else if(leave==1){//最少2步 有没有可能1步完成?,删除一个数,且对3的余数是2//只有一个的特殊情况if(n==1){cout<<1<<endl;return;}per(i,1,n)if(a[i]%3==1){cout<<1<<endl;return;}cout<<2<<endl;}else if(leave==2){//最少1步,不可能成为0步cout<<1<<endl;}
}void init(){sum=0;
}
signed main(){ios::sync_with_stdio(false),cin.tie(nullptr);int t;cin>>t;while(t--)solve(),init();return 0;
}
C. Turtle Fingers: Count the Values of k
l,a,b已知,x,y任选,问满足条件的k有几个。
因为是求k,所以改一下式子。
题目说了x和y是正整数或者0。所以下面就是一堆a*a*a*a*a*b*b*b*b,任意的a和b。
那么如果这个式子能整除,k就是一个合法的值。a和b的范围都是2~100,2^32次轻轻松松达到整数上限,超过了题目 l 的大小,所以我们找一个不超范围太多但是令人放心的大小即可,比如x和y都枚举到100为止。
#include <bits/stdc++.h>
#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define fr first
#define se second
#define endl '\n'
using namespace std;int a,b,l;set<int>s;
map<int,int>f,g;void solve(){cin>>a>>b>>l;int num=1,base=a;f[num]=a;//记录一下 a*a*a*a的值f[0]=1;while(a<=l){num++;a*=base;f[num]=a;}num=1,base=b;g[num]=b;//记录一下 b*b*b*b的值g[0]=1;while(b<=l){//小于等于l就行了,再大就会得到小数,题目中k是整数num++;b*=base;g[num]=b;}per(i,0,100){per(j,0,100){if(f[i] and g[j]){//如果存在的话就算一下是不是能完整除if(l%(f[i]*g[j])==0){s.insert(l/(f[i]*g[j]));//防止重复,把k的值放到set里面,最后输出set的大小}}else break;}}cout<<s.size()<<endl;
}void init(){s.clear();f.clear();g.clear();
}
signed main(){ios::sync_with_stdio(false),cin.tie(nullptr);int t;cin>>t;while(t--)solve(),init();return 0;
}
D. Turtle Tenacity: Continual Mods
给你一个序列A,选出任意一个排列,要求这个序列连续取模过去最终不等于0。
因为是任意的,显然不需要真的去找出这个序列,只需要判断是否可能。
小的数对大的数取模,还是小的数,不会得到0,所以考虑把序列升序。
如:1 2 3 4 5,最终输出的是最小的那个数。
那么对答案有影响的就是重复的数和最小的数了。
如果最小的有两个,1 1 2 3 4 5,那么不管怎么放最终都会得到0。
大的数对小的数取模,假设y>x,那么y % x得到的值范围在0~x-1之间
所以对最小的数重复的情况进行假设:
x x a b c d e f g
x x后面的取值只有两种可能:是x的倍数,不是x的倍数。
如果是倍数,那么取余不会变得更小,会得到0.
如果不是倍数,那么一定会得到更小的数。
再考虑特殊情况,如果后面都是倍数,倍数和倍数之间能否得到比x更小的数。
x x 2*x 3*x 4*x 6*x
显然是不行的,最少取模出来都是x。
所以不需要后面的数相互去取模判断,只需要和x取模即可。
#include <bits/stdc++.h>
#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define fr first
#define se second
#define endl '\n'
using namespace std;
const int N=1e5+5;int n,tmp,minn;
map<int,int>f;
vector<int>v;void solve(){cin>>n;per(i,1,n){cin>>tmp;f[tmp]++;}for(auto [x,y]:f){//第一个就是最小的数if(y==1)cout<<"YES"<<endl;//如果只有一个,则YESelse{minn=x;//否则,记录一下最小值break;}return;}for(auto [x,y]:f){//把所有数都拿出来v.push_back(x);}rep(i,v.size()-1,1){//后面的数和最小的数取模int tmp=v[i]%v[0];if(tmp!=0 and tmp<minn){//能取出更小的,直接输出YES就行cout<<"YES"<<endl;return;}}cout<<"NO"<<endl;
}void init(){f.clear();v.clear();
}
signed main(){ios::sync_with_stdio(false),cin.tie(nullptr);int t;cin>>t;while(t--)solve(),init();return 0;
}
补题:E. Turtle vs. Rabbit Race: Optimal Trainings
这道题太可惜了,赛后一会会就做出来了。
lsaac喜欢跑步。
他跑过第一个阶段会得到u的表现分。
他跑过第二个阶段会得到u-1的表现分。
他跑过第三个阶段会得到u-2的表现分。
......
他跑过第k个阶段会得到u+1-k的表现分。
现在有数组a[n],数组中包含阶段数量,如跑过a[1],若a[1]=3,则直接获得3个阶段。
给你数组起始点L,和表现分开头u,问你总表现分最大的情况下,数组结束点R最小是多少。
首先计算一下总表现分,发现是一个公差为1的等差数列,则总表现分为【(首项+尾项)*项数】/2,即((u+(u+1-k))*k)/2
因为我们只需要找R的位置,而且总表现分从开头到结尾是一个开口向下的抛物线(因为u先是正的然后变成负了,求和先变大再变小),再结合题目告诉我们这道题是多次询问,显然要用二分来确定R的位置。
得到总表现分之前需要得到阶段数,显然需要用前缀和去维护一下,一个一个加太慢了。
最后二分的时候,我们可以假设起始点L就是R的位置,拿mid和他比较。
而mid有两个地方有可能比L大,只有左边的mid,才需要L往右走,所以需要再来一个mid-1来和mid的表现分作比较。(有点类似三分了)
#include <bits/stdc++.h>
#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define fr first
#define se second
#define endl '\n'
using namespace std;
const int N=1e5+5;int n,a[N],q,l,u,f[N];int p(int k){return ((u+(u+1-k))*k)/2;
}void query(){cin>>l>>u;//需要最大的表现分//f[r]-f[l-1]->x 为当前经过的小节数量//第k节获得的表现分y=u+1-k //公差为1的等差数列//表现分[u+(u+1-k)]*k/2// int ans=l;
// per(r,l,n){
// if(p(f[r]-f[l-1])>p(f[ans]-f[l-1])){
// ans=r;
// }
// }
// cout<<ans<<" ";int left=l,right=n;while(left<right){int mid=(left+right)>>1;int rValue=p(f[mid]-f[l-1]);int rpValue=p(f[mid-1]-f[l-1]);int lValue=p(f[left]-f[l-1]);if(rValue>lValue and rpValue<rValue){left=mid;}else right=mid;}if(left==n-1)left=p(f[left+1]-f[l-1])>p(f[left]-f[l-1])?left+1:left;cout<<left<<" ";
}void solve(){cin>>n;per(i,1,n)cin>>a[i],f[i]=f[i-1]+a[i];cin>>q;per(i,1,q)query();cout<<endl;
}void init(){per(i,1,n)f[i]=0;
}
signed main(){ios::sync_with_stdio(false),cin.tie(nullptr);int t;cin>>t;while(t--)solve(),init();return 0;
}
上面的二分是我手写的,l最终没有和最后一个数比较,如果l==n-1的话,还需要和n去比较一次。