2020 CCPC Wannafly Winter Camp Day1 H,F,B,I

H最大公约数


题意

给定两个整数 n , k n,k n,k,找到最小的 y y y,使得 gcd ⁡ ( k , y ) ≤ n \gcd (k,y) \leq n gcd(k,y)n,不存在这样的 y y y,则输出 − 1 -1 1

分析

由于每次给出的结果是 gcd ⁡ ( k , y ) \gcd(k,y) gcd(k,y),因此需要枚举小于等于 n n n的素数 x x x,使得 x ∗ k < n x*k<n xk<n,故累乘之后的结果即为所求。大数模拟即可。


代码


 #include <bits/stdc++.h>
#define fir first
#define sec second
#define pb 	push_back
#define ll  long long
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define pii pair<int,int>
#define debug(x) cerr<<#x<<" =: "<<x<<endl;
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;
#define Find find_by_order
#define Order order_of_key
typedef tree<int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> indexed_set;
mt19937 mrand(random_device{}());
ll rnd(ll x) { return mrand() % x;}
ll ksm(ll a,ll b,ll mod){ll ans=1;a%=mod;while(b){if(b&1) ans=ans*a%mod;b>>=1;a=a*a%mod;}return ans;}
ll phi(ll n){ll ans=n;for(ll i=2;i*i<=n;i++){if(n%i==0) {while(n%i==0) n/=i;ans=ans*(i-1)/i;}}if(n>1) ans=ans*(n-1)/n;return ans;}
//head

string mul(string a, int b) {
    string c;
    char s;
    int len = a.length();
    int ok = 0;
    for (int i = len - 1; i >= 0; i--) {
        int temp = (a[i] - '0') * b + ok;
        ok = temp / 10;
        s = temp % 10 + '0';
        c = s + c;
    }
    while (ok) {
        s = ok % 10 + '0';
        c = s + c;
        ok /= 10;
    }
    return c;
}

bool judge(string a, string b) {
    if (a.size() == b.size()) {
        int sz = a.size();
        for (int i = 0; i < sz; i++) {
            if (a[i] == b[i]) ;
            else return a[i]<b[i];
        }
        return 1;
    }
    return a.size() < b.size();
}
bool isprime(int n){
	for(int i=2;i*i<=n;i++) if(n%i==0) return 0;
	return 1;
}
int solve(int T) {
	int n,k;cin>>n>>k;
	string ans=to_string(k);
	for(int i=2;i<=n;i++){
		if(isprime(i)){
			if(judge(mul(to_string(i),k),to_string(n)))ans=mul(ans,i);
		}
	}
	cout<<ans<<endl;
	return 0;
}
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T=1;
    cin>>T;
    for(int cas=1; cas<=T; cas++) {
        solve(T);
    }
    return 0;
}

F乘法


题意

给定两个序列 A , B A,B A,B,长度分别为 n n n m m m,可以构造出一个 n ∗ m n*m nm的序列 C C C,其中 C i j = A i ∗ B j C_{ij}=A_{i}*B_{j} Cij=AiBj
给出整数 K K K,求 C C C中第 K K K大的值。

分析

显然二分答案 X X X,计算 A [ i ] ∗ B [ j ] ≤ K A[i]*B[j] \leq K A[i]B[j]K的数量,那么 r r r即是答案。
假设当前枚举序列 A A A,二分计算存在多少个乘积严格大于 X X X
A [ i ] < 0 A[i]<0 A[i]<0,需计算 B [ i ] ≤ X / A [ i ] B[i] \leq X/A[i] B[i]X/A[i]的数量。
A [ i ] > 0 A[i]>0 A[i]>0,需计算 B [ i ] < X / A [ i ] B[i]<X/A[i] B[i]<X/A[i]的数量,当前计算的乘积是小于 X X X的数量,故计入的答案为 m − X m-X mX
A [ i ] = = 0 A[i]==0 A[i]==0,乘积必为0,若 X < 0 X<0 X<0,则长度为 m m m B B B序列都满足。
过程可以手动。


代码

#include <bits/stdc++.h>
#define fir first
#define sec second
#define pb  push_back
#define ll  long long
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define pii pair<int,int>
#define debug(x) cerr<<#x<<" =: "<<x<<endl;
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;
#define Find find_by_order
#define Order order_of_key
typedef tree<int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> indexed_set;
mt19937 mrand(random_device{}());
ll rnd(ll x) { return mrand() % x;}
ll ksm(ll a,ll b,ll mod){ll ans=1;a%=mod;while(b){if(b&1) ans=ans*a%mod;b>>=1;a=a*a%mod;}return ans;}
ll phi(ll n){ll ans=n;for(ll i=2;i*i<=n;i++){if(n%i==0) {while(n%i==0) n/=i;ans=ans*(i-1)/i;}}if(n>1) ans=ans*(n-1)/n;return ans;}
//head
 
const int maxn=1e5+7;
vector<ll>va,vb;
int n,m;ll k;
bool judge(ll x){
    ll ret=0;
    for(int i=1;i<=n;i++){
        if (va[i]==0&&x<0) ret+=m;
        else if (va[i]<0) ret+=lower_bound(all(vb),ceil((double)x/va[i]))-(vb.begin()+1);
        else if (va[i]>0) ret+=m-((upper_bound(all(vb),floor((double)x/va[i])))-(vb.begin()+1));
    }
    return ret<=k;
}
// 2
// 2
// 3 4 4 4 5 6 6 6 7
 
int solve(int T) {
    cin>>n>>m>>k;ll x;k--;
    for(int i=1;i<=n;i++) cin>>x,va.pb(x);
    va.pb(-1e14),va.pb(1e14);vb.pb(-1e14),vb.pb(1e14);
    for(int i=1;i<=m;i++) cin>>x,vb.pb(x);
    sort(all(va)),sort(all(vb));
    ll l=-1e13,r=1e13;
    while(r-l>1){
        ll mid=(l+r)/2;
        if(judge(mid)) r=mid;
        else l=mid;
    }
    cout<<r<<endl;
    return 0;
}
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
//    cin>>T;
    int T=1;
    for(int cas=1; cas<=T; cas++) {
        solve(T);
    }
    return 0;
}

B密码


题意

按照题意进行密码的解密过程

分析

签到题,注意密码的解密是逆向的。


代码

n, m = map(int, input().split())
o = []
s = []


def t1(c):
    if c > 'Z':
        return int(ord(c) - ord('a'))
    else:
        return int(ord(c) - ord('A') + 26)


def t2(c):
    if c < 26:
        return chr(c + ord('a'))
    else:
        return chr(c + ord('A') - 26)


def tr(s, t):
    j = 0
    c = ""
    for i in range(len(t)):
        if j >= len(s):
            j = 0
        c += (t2((t1(t[i]) - t1(s[j]) + 52) % 52))
        j += 1
    return c


for i in range(m):
    o.append(list(map(int, input().split())))
for i in range(n):
    s.append(input())
for i in range(m - 1, -1, -1):
    s[o[i][1] - 1] = tr(s[o[i][0] - 1], s[o[i][1] - 1])
for i in range(n):
    print(*s[i], sep='', end='\n')


I–K小数查询


题意

给出一个长度为 n n n的数列 A A A,接下来有 m m m 次操作,操作有两种:

  • 1   l   r   x 1\ l\ r\ x 1 l r x ,表示 i ϵ [ l , r ] i\epsilon [l,r] iϵ[l,r],令 A i = m i n ( A i , x ) A_i=min(A_i,x) Ai=min(Ai,x)
  • 2   l   r   k 2\ l\ r\ k 2 l r k ,表示询问区间 [ l , r ] [l,r] [l,r]中第 k k k小的数。
    其中: 1 ≤ n , m ≤ 8 ∗ 1 0 4 , 1 ≤ A i ≤ n , 1 ≤ x , k ≤ 1 0 9 1 \leq n,m \leq 8*10^4, 1 \leq A_i \leq n,1 \leq x ,k\leq 10^9 1n,m8104,1Ain,1x,k109

分析

直接分块,维护区间最大的数。
查询第k小,暴力二分即可


代码

#include<bits/stdc++.h>
using namespace std;

const int maxn=1e5+7;
int a[maxn],n,blo,pos[maxn],m;

vector<int>vec[1000];

int Max[maxn];

void reset(int id){
    vec[id].clear();
    for(int i=(id-1)*blo+1;i<=min(n,id*blo);i++) vec[id].push_back(a[i]);
    sort(vec[id].begin(),vec[id].end());
}


void update (int l,int r,int x){
    if(pos[l]==pos[r]){
        for(int i=l;i<=r;i++) a[i]=min(a[i],x);
        reset(pos[l]);
    }
    else {
        for(int i=l;i<=pos[l]*blo;i++) a[i]=min(a[i],x);
        reset(pos[l]);
        for(int i=pos[l]+1;i<=pos[r]-1;i++) Max[i]=min(Max[i],x);
        for(int i=(pos[r]-1)*blo+1;i<=r;i++) a[i]=min(a[i],x);
        reset(pos[r]);
    }

}

int get(int l,int r,int x){
    int ans=0;
    if(pos[l]==pos[r]){
        for(int i=l;i<=r;i++) ans+=(min(a[i],Max[pos[l]])<=x);
        return ans;
    }

    for(int i=pos[l]+1;i<=pos[r]-1;i++){
        if(Max[i]<=x) ans+=blo;
        else ans+=upper_bound(vec[i].begin(),vec[i].end(),x)-vec[i].begin();
    }

    for(int i=l;i<=pos[l]*blo;i++) ans+=(min(a[i],Max[pos[l]])<=x);
    for(int i=(pos[r]-1)*blo+1;i<=r;i++) ans+=(min(a[i],Max[pos[r]])<=x);
    return ans;
}

int main (){
    scanf("%d %d",&n,&m);
    blo=sqrt(1.0*n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),pos[i]=(i-1)/blo+1;
    for(int i=1;i<=pos[n];i++){
        Max[i]=0;
        for(int j=(i-1)*blo+1;j<=min(i*blo,n);j++)
            vec[i].push_back(a[j]),Max[i]=max(Max[i],a[j]);
        sort(vec[i].begin(),vec[i].end());
    }
    for(int cas=1;cas<=m;cas++){
        int op,l,r,k;scanf("%d %d %d %d",&op,&l,&r,&k);

        if(op==1) update(l,r,k);
        else {
            int L=1,R=n,ans;
            while(R-L>100){
                int mid=(L+R)/2,cnt=get(l,r,mid);
                if(cnt>=k) R=mid;
                else L=mid;
            }
            for(int i=L;i<=R;i++){
                if(get(l,r,i)>=k) {
                    printf("%d\n",i);
                    break;
                }
            }
//            printf("%d\n",L);
        }
    }
    return 0;
}



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值