A:思维
题意:箱子里有N个颜色的球(用下标代表不同的颜色),每个颜色的球对应一定的数量,你会进行多次拿球的操作,当箱子里的球颜色一致时,你就不能再拿球了,问最后颜色一致的球是哪个球?
方法:其实很简单,最多颜色的球就是答案。因为它的数量是最多的,别的球都取完了,剩下的一定是它。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
struct Node{
int x;
int idx;
}a[N];
bool cmp(Node a,Node b){
return a.x>b.x;
}
inline void solve(){
int n;cin>>n;
for(int i=1;i<=n;i++){
int q;cin>>q;
a[i].x=q;
a[i].idx=i;
}
sort(a+1,a+1+n,cmp);
cout<<a[1].idx<<"\n";
}
int main(){
int T;cin>>T;
while(T--) solve();
}
B:构造
题意:定义一个排序的价值value为:初始有一个x,从第一个元素p1开始,如果x < p1,x += p1,else x = 0,如此循环,最终x的值为该排列的总价值。请构造一个排列使得该价值最大。
分析:我们发现,max=n+n-1。所以我们必须构造一个数组,使得倒数第三个位置的值为0,这样才能保证得到最大值 。当n为偶数时候,我们发现,构造为... n-2,n-3,...1,n-1,n,数字1的位置会是0.如果n为奇数时,我们可以将1放在最前面,构造为1,...n-2,n-3,....3,2,n-1,n.数字2的位置会是0。
代码:
#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
inline void solve(){
int n;cin>>n;
if(n%2==0){
for(int i=n-2;i>=1;i--) cout<<i<< " ";
cout<<n-1<<" "<<n<<"\n";
}
else{
cout<<1<< " ";
for(int i=n-2;i>=2;i--) cout<<i<< " ";
cout<<n-1<<" "<<n<<"\n";
}
}
signed main(){
fast;
int T;cin>>T;
while(T--) solve();
}
C:思维+贪心
题意:给定两个数组a和b,每次进行一次操作可以使其中一个数组中的一个数变成其十进制的位数。求使得在不考虑顺序的情况下,a和b数组相等的最少操作数。
思路:考虑开两个堆,每次从大到小贪,因为大的数字只能变小。如果堆顶相同直接将这两个元素pop掉。如果不同,将更大的数字操作一次重新放到堆里,因为这个数一定没有其他数可以与之匹配。一直进行到堆顶都为1即可。
代码:
#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int a[N],b[N];
int get(int x){
int ans=0;
while(x){
ans++;
x/=10;
}
return ans;
}
inline void solve(){
int n;cin>>n;
priority_queue<int>aa,bb;
for(int i=1;i<=n;i++) cin>>a[i],aa.push(a[i]);
for(int i=1;i<=n;i++) cin>>b[i],bb.push(b[i]);
int ans=0;
while(aa.size()&&bb.size()&&(aa.top()>1||bb.top()>1)){
bool ok=false;
while(aa.size()&&bb.size()&&aa.top()==bb.top()){
aa.pop();bb.pop();
ok=true;
}
if(ok) continue;
if(aa.top()>bb.top()){
int x=aa.top();
ans++;aa.pop();
aa.push(get(x));
}
else{
int x=bb.top();
ans++;bb.pop();
bb.push(get(x));
}
}
cout<<ans<<"\n";
}
signed main(){
fast;
int T;cin>>T;
while(T--) solve();
}
D:博弈
题意:给定一个字符串,两人每次可以从头和尾拿走一个字符,拿走的字符放到字符串的开头,字典序小的人获胜,求最终谁赢或者平手。
分析:我们发现,Alice先手,那么Bob就不可能赢,Bob所能争取的最大情况就是Draw(平局)。为什么?
因为,Alice先手,那么Alice一定会选择字母最小的,Bob不是傻子,如果字符串为abaa,Alice选择了a,剩余字符串为ab,那么Bob肯定会选a。所以,Bob会尽量使自己平局,那么Alice肯定想赢,所以,我们只需要判断满足平局的字符串即可。不满足平局的字符串,就一定是Alice赢!
那么这里的问题就在于:平局字符串有什么性质?
举几个平局的串:aabbcc acbbca.....发现什么特点了吗?
特点:如果每个相同的字母都满足(存在偶数个)位于相邻位置,或者是一个在前面一个在后面的情况,那么就是平局,否则就是Alice赢。所以,这里只需要把串扫一遍即可。
代码:
#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
inline void solve(){
string s;cin>>s;
int n=s.size();
bool ok=false;
for(int i=0;i<n/2+1;i++){
if(s[i]!=s[n-i-1]){
for(int j=i;j<n-i-1;j+=2){
if(s[j]!=s[j+1]) ok=true;
}
break;
}
}
if(ok) cout<<"Alice\n";
else cout<<"Draw\n";
}
signed main(){
fast;
int T;cin>>T;
while(T--) solve();
}