A
签到题,略
B
题意:
给定长度为n的序列,将其分成k个长度大于m的段,要求最大化 每段前m大的元素的和的和
题解:
显然取全局前m*k大是最优的,根据这m*k大元素将序列分成k段即可
代码:
/**
* ┏┓ ┏┓
* ┏┛┗━━━━━━━┛┗━━━┓
* ┃ ┃
* ┃ ━ ┃
* ┃ > < ┃
* ┃ ┃
* ┃... ⌒ ... ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ Code is far away from bug with the animal protecting
* ┃ ┃ 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━━━━━━━━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<set>
#include<bitset>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 200005
#define nm 200005
#define pi 3.1415926535897931
const int inf=1e9+7;
using namespace std;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
int n,m,k,a[NM],tmp[NM],x;
ll ans;
bool v[NM];
bool cmp(int x,int y){return a[x]>a[y];}
int main(){
n=read();m=read();k=read();
inc(i,1,n)a[i]=read(),tmp[i]=i;
sort(tmp+1,tmp+1+n,cmp);
inc(i,1,m*k)v[tmp[i]]++,ans+=a[tmp[i]];
printf("%lld\n",ans);
inc(i,1,k){
inc(j,1,m){
x++;
while(x<=n&&!v[x])x++;
}
if(i<k)printf("%d ",x);
}
putchar('\n');
return 0;
}
C
题意:
求出n!在b进制下的末尾0的个数
题解:
参照10进制末尾0的算法,对b进行素因子分解,然后统计n!中每个素因子的数量,考虑到p^k的存在,所以要做一点小容斥
注意部分地方爆ll
代码:
/**
* ┏┓ ┏┓
* ┏┛┗━━━━━━━┛┗━━━┓
* ┃ ┃
* ┃ ━ ┃
* ┃ > < ┃
* ┃ ┃
* ┃... ⌒ ... ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ Code is far away from bug with the animal protecting
* ┃ ┃ 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━━━━━━━━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<set>
#include<bitset>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 200005
#define nm 200005
#define pi 3.1415926535897931
const ll inf=9e18;
using namespace std;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
ll n,m,a[NM],cnt[NM],ans,tot;
int main(){
n=read();m=read();
for(ll i=2;i*i<=m;i++)if(m%i==0){
a[++tot]=i;while(m%i==0)m/=i,cnt[tot]++;
}
if(m>1)a[++tot]=m,cnt[tot]=1;
ans=inf;
inc(i,1,tot){
ll s=0;
for(ll k=a[i],j=1;k<=n;k*=a[i],j++)
if(n/k>=a[i])s+=j*(n/k-n/(k*a[i]));
else{
s+=j*(n/k);
break;
}
ans=min(ans,s/cnt[i]);
}
return 0*printf("%lld\n",ans);
}
D
题意:
将连续的有相同数字的段称为一个联通块
从某一个位置出发,将其所在的联通块的所有数字,变成任意一个数字,问最少用多少步能使得整个序列变成一个联通块
题解:
先对序列去重(去重之后长度为n),考虑个个数字两两不同的情况,那么需要n-1次操作,更少的操作得益于类似212的情况,即2侧的联通块的数字相同的情况,出现一次操作数减一,因此需要枚举每个点出发,看2侧能够形成的配对对有多少就行
其实这个配对对就是将枚举点一侧翻转过来求LCS,那么直接整体翻转后求LCS,再来枚举匹配点就可以了
代码:
/**
* ┏┓ ┏┓
* ┏┛┗━━━━━━━┛┗━━━┓
* ┃ ┃
* ┃ ━ ┃
* ┃ > < ┃
* ┃ ┃
* ┃... ⌒ ... ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ Code is far away from bug with the animal protecting
* ┃ ┃ 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━━━━━━━━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<set>
#include<bitset>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 5005
#define nm 200005
#define pi 3.1415926535897931
const ll inf=9e18;
using namespace std;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
int a[NM],b[NM],d[NM][NM],ans,n,m;
int main(){
n=read();inc(i,1,n)a[i]=read();
inc(i,1,n)if(a[i]!=a[i+1])b[++m]=a[i];
n=m;inc(i,1,n)a[i]=b[i];
reverse(b+1,b+1+n);
inc(i,1,n)inc(j,1,n){
d[i][j]=max(d[i][j-1],d[i-1][j]);
if(a[i]==b[j])d[i][j]=max(d[i][j],d[i-1][j-1]+1);
}
inc(i,1,n-1)ans=max(ans,d[i][n-i]);
return 0*printf("%d\n",n-1-ans);
}
E
题意:
给出一个等差数列将其乱序,你有2种询问操作:
1.“? i",询问ai的值
2."> x",询问序列中是否有元素大于x
要在60次询问内询问出该序列的首项和公差
题解:
显然二分30次可以查出序列的最大值,还要用30次得到等差的另一个信息,其实可以随机选30个数询问然后得到差值求gcd得到d。如果数据随机,那么相当于在0~n-1的排列中选30个数使得这些数的gcd为1,这个其实还是比较好做到的。
然后关键在怎么随机(
如果能用时间随机种子这题估计场上就过了。。
不能的话自己弄一个随机种子吧。。有被对着卡的风险。。(好在现在没人卡泥了
要问有没有靠谱点的做法->黑科技介绍:mt19937
代码 :
/**
* ┏┓ ┏┓
* ┏┛┗━━━━━━━┛┗━━━┓
* ┃ ┃
* ┃ ━ ┃
* ┃ > < ┃
* ┃ ┃
* ┃... ⌒ ... ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ Code is far away from bug with the animal protecting
* ┃ ┃ 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━━━━━━━━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<set>
#include<bitset>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 5005
#define nm 200005
#define pi 3.1415926535897931
const int inf=1e9+7;
using namespace std;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
int n,ans,s,cnt,t;
int main(){
srand(19260817);
scanf("%d",&n);
for(int x=0,y=1e9-1;x<=y;){
printf("> %d\n",mid);
fflush(stdout);
s++;
scanf("%d",&t);
if(t)ans=x=mid+1;else y=mid-1;
}
cnt=0;
inc(i,1,min(60-s,n)){
printf("? %d\n",(rand()*rand()+rand())%n+1);
fflush(stdout);
scanf("%d",&t);
cnt=__gcd(cnt,ans-t);
}
printf("! %d %d\n",ans-(n-1)*cnt,cnt);
return 0;
}
F
泥萌的汪聚聚一上来就把f切了