A博弈(队友过的)
B水题
C复杂的线段树(没看明白,待补)
D水题
E大模拟恶心的bfs
F水题
G思维题
H数论知识a=b+m如果m%x!=0那么a%x不等于b%x,另外需要用FFT
I求期望,概率DP(待补,概率DP专题)
J比C题简单的优美线段树(看明白了,题解和C一起写吧)
K出题人鼓励大家乱搞实际上也是乱搞
G
题意:给长度为N的A、B两组序列,要求交换A中的两个不同元素,恰好进行K次交换。使得A、B对应位置的数之差的绝对值加起来尽可能大,输出这个值
思考:
怎么交换才能让值变得更优呢?考虑有四个数,a>b>c>d ,它们组成数对。如果a对应的不是b,那么b就会对应c或者d。此时a、b都会因为在数对中较大而获得正号。那么此时四个数的符号分布就是+a,+b,-c,-d。此时已是最优解。所以只有当a对应b时,我们才有更改的必要,因为此时是+a,-b(c、d不确定也不用管)。也就是说,对于A与B形成的两个数对(a1,b1)和(a2,b2),只有当min(a1,b1)>max(a2,b2)时(或者min(a2,b2)>max(a1,b1),两者没有区别),我们才需要交换a1,a2来得到更优解。且此时值增加了2*(min(a1,b1)-max(a2,b2))
另外发现,当n>2时,最终解一定会存在两个数对中A元素符号都为正或者都为负,此时交换两个元素符号是没有任何影响的。所以是可以进行“无效交换”的,这点也就让题目的“恰好交换K次”变成了“最多交换K次”。
解析:因为交换满足min(a1,b1)>max(a2,b2)这一条件的数对时才有作用,且增加的值为2*(min(a1,b1)-max(a2,b2)),所以只需要取min(a,b)尽可能大的,以及max(a,b)尽可能小的,都取K个(如果满足条件的不足K个则能取多少是多少),再进行处理即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll a[500050],b[500050];
ll mi[500050],ma[500050];
ll ans=0;
int main()
{
ll n,k;
scanf("%lld%lld",&n,&k);
for(ll i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(ll i=1;i<=n;i++)
scanf("%lld",&b[i]);
if(n==2)//考虑特殊情况
{
if(k%2==1)
swap(a[1],a[2]);
ans=abs(a[1]-b[1])+abs(a[2]-b[2]);
printf("%lld\n",ans);
return 0;
}
for(ll i=1;i<=n;++i)
ans+=abs(a[i]-b[i]);
for(ll i=1;i<=n;++i)
{
mi[i]=min(a[i],b[i]);
ma[i]=max(a[i],b[i]);
}
sort(mi+1,mi+1+n);
sort(ma+1,ma+1+n);
for(ll i=1;i<=k&&i<=n;++i)
{
if(mi[n-i+1]>ma[i]) //min(a,b)取大的,max(a,b)取小的
ans+=2*(mi[n-i+1]-ma[i]);
else
break;
}
printf("%lld\n",ans);
return 0;
}
H
题意:给一个长度为N的非负整数序列,序列中数两两不相同,找一个最小数x,使得序列中所有数对x取余后都不同,N<=500000,ai<=500000
解析:取余不同则想到a=b+m,若m%x!=0,则a%x不同于b%x。那么要使得所有的数对x取余后两两互不相同,则需要所有的数两两之差都不能整除于x,且x最小。后面求x比较简单,算N个数两两之差当然就是用FFT了,利用多项式相乘即指数相加来做。(加减用指数,相乘用系数)因为是之差所以需要设一个偏移量。两个多项式一个指数直接是ai,一个指数是500050-ai。最后结果再-500050即可。(比赛的时候把前一个ai+500050结果T了半天最后发现根本没必要加这个500050…)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e6+50;
const double pi=acos(-1);
ll r[N],bits;
complex<double>A[N],B[N],w[N];
int dp[500005], vis[500005];
void FFT(complex<double> *P,ll op,ll N)
{
for(ll i=1;i<N;i++)
{
if(i>r[i])
swap(P[i],P[r[i]]);
}
for(ll i=1;i<N;i<<=1)
{
for(ll p=i<<1,j=0;j<N;j+=p)
{
for(ll k=0;k<i;k++)
{
complex<double>W=w[N/i*k];
W.imag(W.imag()*op);
complex<double> X=P[j+k],Y=W*P[j+k+i];
P[j+k]=X+Y;
P[j+k+i]=X-Y;
}
}
}
}
ll a[N],b[N],cnt[N];
void solve(ll *a,ll *b,ll n,ll m)
{
ll len;
for(len=1,bits=0;len<=n+m;len<<=1)
bits++;
bits--;
for(ll i=0;i<len;i++)
A[i].real(0),A[i].imag(0),B[i].real(0),B[i].imag(0);
for(ll i=0;i<=n;i++)
A[i].real(a[i]);
for(ll i=0;i<=m;i++)
B[i].real(b[i]);
for(ll i=0;i<len;i++)
r[i]=(r[i>>1]>>1)|((i&1)<<bits);
for(ll i=0;i<len;i++)
w[i].real(cos(pi/len*i)),w[i].imag(sin(pi/len*i));
FFT(A,1,len);
FFT(B,1,len);
for(ll i=0;i<len;i++)
A[i]=A[i]*B[i];
FFT(A,-1,len);
for(ll i=0;i<=n+m;i++)
a[i]=(ll)(A[i].real()/len+0.5);
}
ll hh[1500150];
ll cii=0;
int main()
{
ll n,m,k,x;
scanf("%lld",&n);
for(ll i=0;i<n;i++)
{
scanf("%lld",&x);
a[x]=1;
b[500050-x]=1;
}
solve(a,b,500050,500050);
//printf("a=%lld \n",a[1000]);
for(ll i=0;i<=1000100;i++)
{
if(a[i]!=0)
hh[cii++]=abs(i-500050);
}
int Max=0;
for(ll i=0;i<cii;i++)
{
if(hh[i]>Max)
{
Max=hh[i];
}
dp[hh[i]]=1;
}
int ans=Max+1;
for(int i=Max;i>=n;i--)
{
if(dp[i]==0)
{
ans=i;
continue;
}
if(vis[i]==1)
{
continue;
}
for(int j=2;j*j<=i;j++)
{
if(i%j==0)
{
vis[j]=1;
vis[i/j]=1;
dp[j]=1;
dp[i/j]=1;
}
}
}
printf("%d\n",ans);
return 0;
}
272

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



