• 【模拟赛】纪中提高A组 19.8.18 测试


    Task.1 完全背包

    题目大意:物品 (n) 件,背包体积 (m),物品体积 (a_i) 价值 (b_i),每件物品无数件。求不超过容量上限的最大价值。

    数据范围:(1leq Nleq 10^6,1leq Mleq 10^{16},a_i,b_ileq 100)

    题如其名,真的是完全背包。观察数据范围后发现对于 (a_i,b_i)(a_i) 相同的明显可以舍弃 (b_i) 小的,物品数量下降至 (100)。比较容易想到在一定范围内,贪心地选取单位体积价值大的物品,小范围内做背包。至于这个范围的大小题解给做出了相关讨论:

    引理:给定任意 (n) 个整数,它们之中存在若干个整数的和为 (n) 的倍数。

    定理:假设贪心的选取若干件性价比最高的物品,此外选择 (x) 件其他的物品是最优的情况,那么存在一种最优情况使得 (xleq val_{max})

    至于证明?想想为什么。


    此外还存在一种矩阵优化普通的 (dp) 的做法。

    通常的矩阵加速递推是形如 (f_i=sum^{i-1}_{j=i-k} c_{i-j}cdot f_j) 的形式,用普通的矩乘就能优化。对于 (min/max) 一类的操作,他们和加法具有类似的性质。如果定义一种矩阵的取 (max) 运算((A max B=C,c_{i,j}=max{max(a_{i,k},b_{k,j})})),这种运算满足结合律,也可以用矩乘快速幂优化。

    代码请转至:https://www.cnblogs.com/15owzLy1-yiylcy/protected/p/11379610.html

    鸣谢 (15owzly1)

    Task.2 中间值

    题目大意:有两个长度均为 (n) 的单增不降序列 (a,b),给出 (m) 次修改和查询操作。每次修改操作给出参数 (s,x,y) ,表示修改 (a [s=0])(b [s=1]) 中的位置 (x) 上的值为 (y),保证修改操作不破坏单增不降的性质。查询操作给出区间 ([l_1,r_1],[l_2,r_2]),询问两段区间合并后的 (k) 中位数,保证查询操作两区间长度和为奇数。

    数据范围:(1leq Nleq 5cdot 10^5,1leq Mleq 10^6,0leq a_i,b_i,yleq 10^9,1leq l_1leq r_1leq N,1leq l_2leq r_2leq N)

    修改操作可以 (O(1))

    可以想到一个二分的做法:二分一个数字作为中位数,每次在两段区间中二分这个数的位置,判断答案是否合法。单次查询复杂度 (O(log^2 N))。期望得分 (70) (还要卡一卡,所以我没写)。

    考虑换个二分的对象,二分答案在一个序列中的位置,再根据位置去另一个序列的期望位置判断合不合法,这样单次就只有 (O(log N))

    代码:

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    
    template<class T>void read(T &x){
    	x=0; char c=getchar();
    	while(c<'0'||'9'<c)c=getchar();
    	while('0'<=c&&c<='9'){x=(x<<1)+(x<<3)+(c^48); c=getchar();}
    }
    
    const int N=500050;
    
    int n,m;
    int a[N],b[N];
    int inf=1e9+1,fni=-1e9-1;
    
    int solve(int La,int Ra,int Lb,int Rb){
    	int l=La,r=Ra,mid;
    	int len=(Ra+Rb-La-Lb+2)>>1,pos;
    	swap(b[Lb-1],fni); swap(b[Rb+1],inf);
    	while(l<=r){
    		mid=(l+r)>>1;
    		pos=Lb+len-(mid-La+1);
    		if(pos+1<Lb){r=mid-1; continue;}
    		if(pos-1>Rb){l=mid+1; continue;}
    		if(b[pos]<=a[mid]&&a[mid]<=b[pos+1]){
    			swap(b[Lb-1],fni); swap(b[Rb+1],inf);
    			return a[mid];
    		}
    		if(b[pos]>a[mid])l=mid+1;
    		else r=mid-1;
    	}
    	swap(b[Lb-1],fni); swap(b[Rb+1],inf);
    	
    	l=Lb; r=Rb;
    	swap(a[La-1],fni); swap(a[Ra+1],inf);
    	while(l<=r){
    		mid=(l+r)>>1;
    		pos=La+len-(mid-Lb+1);
    		if(pos+1<La){r=mid-1; continue;}
    		if(pos-1>Ra){l=mid+1; continue;}
    		if(a[pos]<=b[mid]&&b[mid]<=a[pos+1]){
    			swap(a[La-1],fni); swap(a[Ra+1],inf);
    			return b[mid];
    		}
    		if(a[pos]>b[mid])l=mid+1;
    		else r=mid-1;
    	}
    	swap(a[La-1],fni); swap(a[Ra+1],inf);
    }
    
    int main(){
    //	freopen("median.in","r",stdin);
    //	freopen("median.out","w",stdout);
    	read(n); read(m);
    	for(int i=1;i<=n;i++) read(a[i]);
    	for(int i=1;i<=n;i++) read(b[i]);
    	int opt,x,y,l,r;
    	while(m--){
    		read(opt); read(x); read(y); read(l);
    		if(opt==1){if(x)b[y]=l;else a[y]=l;}
    		else {
    			read(r);
    			printf("%d
    ",solve(x,y,l,r));
    		}
    	}
    	return 0;
    }
    

    还有一种思路是每次在每个区间取中间值,然后比较大小分类讨论扔掉一部分区间。

    Task.3 Sequence

    题目大意:定义序列 (A) 的价值为 (gcd(a_1,a_2,a_3,...a_n,B))(B) 为给出的定值。定义 (f(i)) 为所有的长度为 (n),由 (i) 的约数组成的序列的价值和。给出 (n,m,B),求 (sum^m_{i=1} f(i))

    数据范围:(N,Bleq 10^{18},Mleq 2cdot 10^7)

    考虑某一个 (i) 的约数组成的序列,若 (i)(c_i) 个约数,(i) 对应得序列数量为 (c_i^n),每个序列的价值一定是 (B) 的约数。

    对于一个质数 (p)(p) 对应的序列可能的价值取值只有;两种:(1)(p) (如果 (p)(B) 的约数),(1)

    明早继续解释。

  • 相关阅读:
    【linux】驱动-13-阻塞与非阻塞
    【linux】驱动-12-并发与竞态
    【linux】驱动-11-gpio子系统
    【linux】驱动-10-pinctrl子系统
    【linux】驱动-9-设备树插件
    手写Java分页模块
    JDBC连接与自定义线程池
    类加载器
    网络编程之TCP
    网络编程之UDP
  • 原文地址:https://www.cnblogs.com/opethrax/p/11372825.html
Copyright © 2020-2023  润新知