【乱搞】【DBSDFZOJ 4415】黄金拼图

题目描述

Description:
九条可怜有 n 盒拼图,每盒拼图都有若干拼图块,可以拼出许多矩形图案。可是,可怜经常会弄丢拼图块,因此她需要将一些拼图送回厂家进行补块。可怜懒得将所有拼图拼好来检查完整性,仅当她的一盒拼图的拼图块数无法组成任何 r 块×c 块的矩形图案(其中 r,c≥2),可怜才认为这盒拼图需要返厂补块。返厂补块需要的运费只和含有图块数最多的拼图有关。
可怜将 n 盒拼图从 1 到 n 编号。每次,可怜都想知道,如果从编号在[l,r]区间内的拼图中选择 k 盒一定需要补块的拼图,拼图块数最多的拼图的拼图块数最少是多少。当然,可怜只是随口问问,并不会真的将这些拼图返厂,所以询问后所有拼图的块数都不会变化。
有时,可怜会发现自己数错了拼图的块数,并将第 x 盒拼图的拼图块数更新为 y。她希望你能即时回答这些询问。
Input:
第一行两个整数 n,k,m,m 表示可怜询问和修改的数量和。
接下来一行 n 个正整数,第 i 个数表示第 i 盒拼图初始时的拼图块数。
接下来 m 行,每行 3 个数 opt,l,r。为了表明你在即时回答可怜的询问,真实的 opt,l,r 为输入的 opt,l,r 分别异或(XOR)lastans,其中 lastans 表示上一次询问的答案,若之前没有询问操作,则 lastans=0。
若opt=1,则表示这是一次询问操作,询问的区间为[l,r]。
若opt=2,则表示这是一次修改操作,把第 l 盒拼图的块数修改为 r。
Output:
对于每个询问操作,输出一行一个整数,表示拼图块数最多的拼图的拼图块数最少是多少。保证答案存在。
Sample Input 1:
3 1 3
4 5 6
1 1 3
7 7 2
4 4 6
Sample Output 1:
5
7
Sample Input 2:
3 2 3
4 5 7
1 1 3
5 4 2
6 6 4
Sample Output 2:
7
5

Data Constraint:
对于 30%的数据,n,m≤1000。
对于另 30%的数据,没有修改操作。
对于 100%的数据,1≤n,m,k≤200000,l,r 合法,所有拼图的块数在任何时刻是[4,1000000]区间中的整数。

解题思路

我们可以发现 lastans 一定是一个大于4的质数,因此lastans的二进制最低位一定是 1。由于opt是1或者2,所以可以根据opt的奇偶性判定lastans的值。反解出答案,只有最后一个操作是询问时需要暴力处理,预处理出质数后将最后一个询问的区间排序后暴力查询就可以了。
复杂度 O(v log v) ,其中 v 表示值域。若使用线性筛,可以做到复杂度 O(v) 。

代码

#include<bits/stdc++.h> 
#define ll long long 
using namespace std; 
int n,m,k,a[200005],b[200005]; 
bitset<1000005>pd; 
inline void ks(){ 
    for(int i=2;i<=1000005;++i){ 
        if(pd[i]==0){ 
            int t=i+i; 
            while(t<1000005){ 
                pd[t]=1; 
                t+=i; 
            } 
        } 
    } 
} 
int main(){ 
    ks(); 
    scanf("%d%d%d",&n,&k,&m); 
    for(int i=1;i<=n;++i){scanf("%d",&a[i]);} 
    int opt,l,r,lastans=0; 
    if(n<=1000&&m<=1000){
        for(int i=1;i<=m;++i){
            scanf("%d%d%d",&opt,&l,&r); 
            opt^=lastans;l^=lastans;r^=lastans; 
            if(opt==1){ 
                for(int i=l;i<=r;++i){if(pd[a[i]]==0)b[++b[0]]=a[i];} 
                sort(b+1,b+b[0]+1); 
                printf("%d\n",b[k]); 
                lastans=b[k]; 
                b[0]=0; 
            } 
            else a[l]=r; 
        } 
    } 
    else{ 
        for(int i=1;i<=m;++i){
            scanf("%d%d%d",&opt,&l,&r); 
            if(opt%2==1){
                l^=opt^2,r^=opt^2; 
                a[l]=r;
                continue;
            }
            lastans=opt^1; 
            if(i!=1)printf("%d\n",lastans); 
        }
        if(opt%2==1)return 0;;
        l^=opt^1,r^=opt^1; 
        for(int i=l;i<=r;++i){if(pd[a[i]]==0)b[++b[0]]=a[i];} 
        sort(b+1,b+b[0]+1);
        printf("%d\n",b[k]); 
        lastans=b[k]; 
    } 
    return 0; 
} 
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值