A:Ahahahahahahahaha
题意:给定一个01串,01串的长度保证为偶数,问删除最多n/2个元素能否使得奇数位和等于偶数位置和
题解:首先很明显0对于和是没有影响的,所以在原串中0的数量>=n/2那我们就直接输出n/2个0即可,问题就在于1的数量>n/2的时候怎么办。这时若(n/2)%2=0那我们同理输出n/2个1,若(n/2)%2=1,那就输出(n/2)+1个1(因为此时保证1的数量>(n/2))
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll rd(){
ll x=0;char o,f=1;
while(o=getchar(),o<48)if(o==45)f=-f;
do x=(x<<3)+(x<<1)+(o^48);
while(o=getchar(),o>47);
return x*f;
}
const int maxn=1e3+5;
const ll mod=998244353;
ll ksm(ll a,ll b){ll ans=1;while(b){if(b&1)ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll gcd(ll a, ll b){ll t;while(b){t=b;b=a%b;a=t;}return a;}
int _;
int n,a[maxn];
int main() {
for(scanf("%d",&_);_;_--){
n=rd();
for (int i=1;i<=n;i++)a[i]=rd();
int ji=0,ou=0;
for (int i=1;i<=n;i++){
if (a[i]==1)ji++;
else ou++;
}
if (ou>=n/2){
printf("%d\n",n/2);
for (int i=1;i<=n/2;i++)
printf("0 ");
}
else{
if ((n/2)%2==0){
printf("%d\n",n/2);
for (int i=1;i<=n/2;i++)
printf("1 ");
}
else{
printf("%d\n",n/2+1);
for (int i=1;i<=n/2+1;i++)
printf("1 ");
}
}
puts("");
}
return 0;
}
B:Big Vova
题意:给定一个序列,定义c[i]为gcd(b[1]…b[i]),将序列合理排列成b,使得c字典序最大
题解:数据范围就挺明显的 1e3直接n2暴力就可,每次c[i]相当于对于上一次结果和剩下的所有数都尝试做一次gcd把最大的拿过来就行
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll rd(){
ll x=0;char o,f=1;
while(o=getchar(),o<48)if(o==45)f=-f;
do x=(x<<3)+(x<<1)+(o^48);
while(o=getchar(),o>47);
return x*f;
}
const int maxn=1e3+5;
const ll mod=998244353;
ll ksm(ll a,ll b){ll ans=1;while(b){if(b&1)ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
int gcd(int a, int b){int t;while(b){t=b;b=a%b;a=t;}return a;}
int _;
int n,a[maxn],vis[maxn],ans[maxn];
int main() {
for(scanf("%d",&_);_;_--){
n=rd();int mx=0;
for (int i=1;i<=n;i++){
a[i]=rd();vis[i]=0;
if (a[i]>a[mx])mx=i;
}
int now=2,nowx=a[mx];
vis[mx]=1;
ans[1]=a[mx];
for (;now<=n;now++){
int tmp=1,p=0;
for (int i=1;i<=n;i++){
if (vis[i])continue;
if (gcd(nowx,a[i])>=tmp){
p=i;tmp=gcd(nowx,a[i]);
}
}
ans[now]=a[p];
vis[p]=1;
nowx=tmp;
}
for (int i=1;i<=n;i++)
printf("%d ",ans[i]);
cout<<endl;
}
return 0;
}
C:Chocolate Bunny
题解:交互题,有一个长度为n的排列,你最多可以询问2n次a[x]%a[y]的值,然后给出序列的全貌。
题解:首先这题我们需要知道一个小技巧,对于x和y两个不同的数,我们只需要两次询问一定可以得到其中一个数。假设x<y, x%y=x,y%x<x,反之同理,所以我们对整个序列一直做反复的操作可以保证在2n次内得到全部值。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll rd(){
ll x=0;char o,f=1;
while(o=getchar(),o<48)if(o==45)f=-f;
do x=(x<<3)+(x<<1)+(o^48);
while(o=getchar(),o>47);
return x*f;
}
const int maxn=1e4+5;
int n;
int vis[maxn],ans[maxn];
map<int,map<int,int> >v;//赛中代码写的很丑 其实可以有很多更短的写法
int main() {
n=rd();
if (n==1){
printf("! 1\n");
cout.flush();
}
int s=1,e=2;
for (int now=1;now<n;now++){
printf("? %d %d\n",s,e);
fflush(stdout);
scanf("%d",&v[s][e]);
printf("? %d %d\n",e,s);
fflush(stdout);
scanf("%d",&v[e][s]);
if (v[e][s]>v[s][e]){
ans[e]=v[e][s];
vis[v[e][s]]=1;
e++;
}
else{
ans[s]=v[s][e];
vis[v[s][e]]=1;
s=e;
e++;
}
}
int p=0;
for (int i=1;i<=n;i++)
if (vis[i]==0)p=i;
if (ans[s]==0)
ans[s]=p;
else
ans[e]=p;
printf("!");
for (int i=1;i<=n;i++)printf(" %d",ans[i]);
printf("\n");
fflush(stdout);
return 0;
}
D:Discrete Centrifugal Jumps
题意:给定n个高楼的高度,要从1跳到n,问最少跳的步数。
跳法定义为从i到j需满足以下任意一个条件
1:j=I+1.
2:i+1到j-1的高楼全部严格小于i和j的高度
3i+1到j-1的高楼全部严格高于i和j的高度
题解:
条件3与2类似,我们这里就讨论2怎么办。我们开一个单调栈,单调栈的模版就是寻找i后面第一个大于i的下标,那其实变相就是这题i可以跳到j 当然还有i-j之间可能出现k,a[i]=a[k]那就不满足了,这个我们只需要在单调栈处理的时候,每次push之前都判断一下栈顶元素是否相等当前元素,如果相等就pop出去。此题跟单调栈模版题有一点不一样的是,你pop掉最后一个元素之后,是可以从栈顶元素跳过来的,因为相当于当前这个元素是小于栈顶元素里最大的,所以满足条件2.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
inline ll rd(){
ll x=0;char o,f=1;
while(o=getchar(),o<48)if(o==45)f=-f;
do x=(x<<3)+(x<<1)+(o^48);
while(o=getchar(),o>47);
return x*f;
}
const int maxn=3e5+5;
int n,a[maxn],dp[maxn];
stack<int>s1,s2;
int main() {
n=rd();
for (int i=1;i<=n;i++)a[i]=rd(),dp[i]=inf;
dp[1]=0;
s1.push(1);s2.push(1);
for (int i=2;i<=n;i++){
while (!s1.empty()&&a[s1.top()]<a[i]){
dp[i]=min(dp[i],dp[s1.top()]+1);
s1.pop();
}
if (!s1.empty()){
dp[i]=min(dp[i],dp[s1.top()]+1);
if (a[s1.top()]==a[i])s1.pop();
}
s1.push(i);
while (!s2.empty()&&a[s2.top()]>a[i]){
dp[i]=min(dp[i],dp[s2.top()]+1);
s2.pop();
}
if (!s2.empty()){
dp[i]=min(dp[i],dp[s2.top()]+1);
if (a[s2.top()]==a[i])s2.pop();
}
s2.push(i);
}
cout<<dp[n]<<endl;
return 0;
}
本文精选四道算法竞赛题目,包括字符串操作、序列排列、交互式问题解决及路径寻优,详细解析题意与解题思路,涵盖单调栈、GCD、字符串匹配等算法技巧。
1684

被折叠的 条评论
为什么被折叠?



