题目链接:https://codeforces.com/group/6QKpZkKhsL/contest/265753
最简单的一个题应该是B
这个应该就是倒着推,题目给了你加密的顺序,所以我们逆推这个就可以得到每一次加密前的字符串。
题目大意就是给你一个范围1~n 满足gcd(k,y) 是独一无二的,意思是除了k之外,1~n中没有gcd(i,y)==gcd(k,y)
这个题目首先要知道gcd(k,y)==k,因为如果等于x,且x<k,那么因为x属于1~n,所以gcd(x,y)==x
这样就不满足题目要求了。
所以y一定是k的倍数,因为在这n个数中,可能有很多数都是k的整数倍,那么这个y要满足要求,则必须是
gcd(m*k,y)!=k,所以如果有数是k的素数倍,那么y也一定是这个素数的倍数。
这个会爆long long 。
这个算法是二分,二分这个第k大,然后check。
这个check有点难写,因为有正有负需要分开写。
最后对我来说比较坑的地方是因为取过膜,所以不可以直接除以2,需要乘以2的逆元。
#include<iostream> #include<cstdio> #include<cstring> #include<bits/stdc++.h> #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; const int maxn=1e5+10; typedef long long ll; ll a[maxn],b[maxn]; ll a1[maxn],a2[maxn],b1[maxn],b2[maxn]; ll tota1=0,tota2=0,totb1=0,totb2=0,zera=0,zerb=0; ll n,m,k; bool check(ll x){ ll sum=0; if(x<=0){ sum+=tota1*totb1+tota2*totb2+zera*m+zerb*n-zera*zerb; // printf("sum=%lld\n",sum); if(x==0) return sum>=k; if(sum>=k) return true; x=-x; for(int i=1;i<=tota1&&totb2;i++){ ll t=upper_bound(b2+1,b2+1+totb2,x/a1[i])-b2; if(b2[t]>x/a1[i]||t>totb2) t--; sum+=t; // printf("aa i=%d sum=%lld t=%d %d\n",i,sum,t,totb2); } for(int i=1;i<=tota2&&totb1;i++){ ll t=upper_bound(b1+1,b1+1+totb1,x/a2[i])-b1; // printf("t=%d\n",t); if(b1[t]>x/a2[i]||t>totb1) t--; sum+=t; // printf("i=%d sum=%lld t=%d\n",i,sum,t); } // printf("x=%lld sum=%lld\n",x,sum); return sum>=k; } for(int i=1;i<=tota1&&totb1;i++){ ll val=x/a1[i]; if(x%a1[i]) val++; int t=lower_bound(b1+1,b1+1+totb1,val)-b1; sum+=totb1-t+1; } for(int i=1;i<=tota2&&totb2;i++){ ll val=x/a2[i]; if(x%a2[i]) val++; int t=lower_bound(b2+1,b2+1+totb2,val)-b2; sum+=totb2-t+1; } return sum>=k; } int main(){ scanf("%lld%lld%lld",&n,&m,&k); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); for(int i=1;i<=m;i++) scanf("%lld",&b[i]); for(int i=1;i<=n;i++){ if(a[i]<0) a1[++tota1]=-a[i]; else if(a[i]>0) a2[++tota2]=a[i]; else zera++; } for(int i=1;i<=m;i++){ if(b[i]<0) b1[++totb1]=-b[i]; else if(b[i]>0) b2[++totb2]=b[i]; else zerb++; } sort(a1+1,a1+1+tota1); sort(a2+1,a2+1+tota2); sort(b1+1,b1+1+totb1); sort(b2+1,b2+1+totb2); // printf("%d %d %d %d\n",tota1,tota2,totb1,totb2); ll l=-inf64,r=inf64,ans=0; while(l<=r){ ll mid=(l+r)>>1; if(check(mid)) ans=mid,l=mid+1; else r=mid-1; } printf("%lld\n",ans); return 0; } /* 1 2 2 2 -3 -3 */