牛客周赛+集美大学模拟

I.简单背包问题

题目链接

题目大意

  • n个物品,Q次询问
  • 问满足体积限制为W下,能得到的最大价值
  • W\leq 1e11,v_i\leq 100,w_i\leq 1e9,n\leq 100,Q\leq 1e5

解题思路

  • 体积限制很大,数组开不下
  • 询问次数很多,每次重做背包,时间不行
  • 价值很小,最大价值总量为1e4
  • 考虑将价值放入状态,每次查询去找满足限制的最大价值
  • f[i][j]表示前i个物品得到j价值的最小体积
  • 只用知道考虑完n个物品的结果,滚动掉一维
  • g[i]表示得到大于等于i价值所用的最小体积,即f[n][j]的后缀最小值
  • 对于每次询问,在g上二分查找
  • g[mid]\leq W,则往右找还有更优解,反之,向左找

import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;




public class Main{
	
	public static void main(String[] args) throws IOException{
		
		AReader input=new AReader();
	    PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	    int n=input.nextInt();
	    
	    long[] w=new long[n+1];
	    int[] v=new int[n+1];
	    long[] f=new long[10005];
	    for(int i=1;i<=n;++i) {
	    	w[i]=input.nextLong();
	    	v[i]=input.nextInt();
	    }
	    Arrays.fill(f, Long.MAX_VALUE/2);
	    f[0]=0;
	    for(int i=1;i<=n;++i) {
	    	
	    	for(int j=10001;j>=v[i];--j) {
	    		f[j]=Math.min(f[j],f[j-v[i]]+w[i]);
	    	}
	    	
	    }
	    
	    long[] mi=new long[10005];
	    Arrays.fill(mi, Long.MAX_VALUE/2);
	    for(int i=10001;i>=1;--i) {
	    	mi[i]=Math.min(f[i], mi[i+1]);
	    }
	    int m=input.nextInt();
	    while(m>0) {
	    	long W=input.nextLong();
	    	int l=1,r=10001;
	    	int ans=0;
	    	while(l<=r) {
	    		int mid=(l+r)>>1;

	    		if(mi[mid]<=W) {
	    			ans=mid;
	    			l=mid+1;
	    		}else r=mid-1;
	    	}
	    	out.println(ans);
	    	m--;
	    }
	    out.flush();
	    out.close();
	}
	
	static
    class AReader {
        private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        private StringTokenizer tokenizer = new StringTokenizer("");
        private String innerNextLine() {
            try {
                return reader.readLine();
            } catch (IOException ex) {
                return null;
            }
        }
        public boolean hasNext() {
            while (!tokenizer.hasMoreTokens()) {
                String nextLine = innerNextLine();
                if (nextLine == null) {
                    return false;
                }
                tokenizer = new StringTokenizer(nextLine);
            }
            return true;
        }
        public String nextLine() {
            tokenizer = new StringTokenizer("");
            return innerNextLine();
        }
        public String next() {
            hasNext();
            return tokenizer.nextToken();
        }
        public int nextInt() {
            return Integer.parseInt(next());
        }
 
        public long nextLong() {
            return Long.parseLong(next());
        }
 
    }
}

 J.響符「パワーレゾナンス」

题目链接 

 题目大意

  • op1=\left\{\begin{matrix} a_i=F(a_i) &i\in [l,r] \\ F(x)=2*\left \lfloor \frac{\left | x^3-3x \right |}{3x^2+1} \right \rfloor& \end{matrix}\right.
  • op2=\sum_{i=l}^{r}a_i

解题思路 

  • 带修改的区间求和\rightarrow区间查询 
  • F(x)无法分解为区间操作\rightarrow单点修改
  • a_i只会变小,且a_i=0,F(a_i)=a_i不变,可以答案标记进行去除,若区间上都有标记则直接跳过
  • 由于单点修改,不同区间选取最终都视为对该点操作(在,则变;不在,则不变)
  • 所以打标记的点可以用并查集维护(标记打过后,不会消去),进行缩点,减少遍历

 



import java.io.*;
import java.util.StringTokenizer;




public class Main{
	static
	class BIT{
		int size;
		long[] tr;
		public BIT(int n) {
			size=n;
			tr=new long[n+1];
		}
		public int lowbit(int x) {
			return x&(-x);
		}
		public void update(int x,long y) {
			for(int i=x;i<=size;i+=lowbit(i)) {
				tr[i]+=y;
			}
		}
		public long query(int x) {
			long res=0;
			for(int i=x;i>0;i-=lowbit(i)) {
				res+=tr[i];
			}
			return res;
		}
	}
	static long F(long x) {
		return 2*(Math.abs(x*x*x-3*x)/(3*x*x+1));
	}
	static int[] fa;
	static int find(int x) {
		if(x==fa[x])return x;
		else return fa[x]=find(fa[x]);
	}
	public static void main(String[] args) throws IOException{
		
		AReader input=new AReader();
	    PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	    int n=input.nextInt();
	    int q=input.nextInt();
	    long[] a=new long[n+1];
	    BIT Tree=new BIT(n);
	    fa=new int[n+1];
	    for(int i=1;i<=n;++i) {
	    	a[i]=input.nextLong();
	    	Tree.update(i,a[i]);
	    	fa[i]=i;
	    }
	    
	    while(q>0) {
	    	int op=input.nextInt();
	    	int l=input.nextInt();
	    	int r=input.nextInt();
	    	if(op==1) {
	    		
	    		for(int i=l;i<=r;i=find(i)+1) {
	    			if(a[i]==0) {
	    				fa[find(i-1)]=find(i);//下一次可以直接通过find跳过i
	    			}else {
	    				long change=F(a[i])-a[i];
	    				Tree.update(i, change);
	    				a[i]+=change;
	    			}
	    		}
	    	}else {
	    		out.println(Tree.query(r)-Tree.query(l-1)); 
	    	}
	    	q--;
	    }
	    out.flush();
	    out.close();
	}
	
	static
    class AReader {
        private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        private StringTokenizer tokenizer = new StringTokenizer("");
        private String innerNextLine() {
            try {
                return reader.readLine();
            } catch (IOException ex) {
                return null;
            }
        }
        public boolean hasNext() {
            while (!tokenizer.hasMoreTokens()) {
                String nextLine = innerNextLine();
                if (nextLine == null) {
                    return false;
                }
                tokenizer = new StringTokenizer(nextLine);
            }
            return true;
        }
        public String nextLine() {
            tokenizer = new StringTokenizer("");
            return innerNextLine();
        }
        public String next() {
            hasNext();
            return tokenizer.nextToken();
        }
        public int nextInt() {
            return Integer.parseInt(next());
        }
 
        public long nextLong() {
            return Long.parseLong(next());
        }
 
    }
}


E.小红构造数组 

题目链接

题目大意

  • 给一个数x,求一个素数序列,满足其乘积为x,且序列中相邻两数不相同
  • 不存在则输出-1

 解题思路

  • x进行素数拆分,统计每个素数个数
  • 若有素数的个数大于总个数(总个数为奇数+1)的一半,则必有相邻两数相同,不存在
  • 若无,则奇数偶数,依次隔一放一个
  • 优化:先将素数2筛出,之后for可以直接跳过所有偶数,减少时间

import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;




public class Main{
	static
	class Node{
		int cnt;
		long x;
	}
	public static void main(String[] args) throws IOException{
		
		AReader input=new AReader();
	    PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	    long x=input.nextLong();
	    if(x==1) {
	    	out.println("-1");
            out.flush();
            return ;
	    }
	    Node[] isp=new Node[101];
	    int cnt=0;
	    
	    int ans=0;
	    while(x%2==0) {
	    	if(cnt==0) {
	    		cnt++;
	    		isp[cnt]=new Node();
	    		isp[cnt].x=2;
	    	}
	    	isp[cnt].cnt++;
	    	x/=2;
	    	ans++;
	    }
	    for(long i=2;i*i<=x;i++) {
	    	if(x%i==0) {
	    		cnt++;
	    		isp[cnt]=new Node();
	    		isp[cnt].x=i;
	    		while(x%i==0) {
	    			ans++;
	    			x/=i;
	    			isp[cnt].cnt++;
	    		}
	    	}
	    }
	    if(x>1) {
	    	cnt++;
    		isp[cnt]=new Node();
    		isp[cnt].x=x;
    		isp[cnt].cnt=1;
    		ans++;
	    }
	   Arrays.sort(isp,1,cnt+1,(o1,o2)->{
		   return o2.cnt-o1.cnt;
	   });
	   if(isp[1].cnt>(ans+1)/2) {
		   out.println("-1");
	   }else {
		   out.println(ans);
		   int t=1;
           long[] oup=new long[ans+1];
		   for(int i=1;i<=ans;i+=2) {
			   if(isp[t].cnt==0)t++;
			   isp[t].cnt--;
			   oup[i]=isp[t].x;  
		   }
		   for(int i=2;i<=ans;i+=2) {
			   if(isp[t].cnt==0)t++;
			   isp[t].cnt--;
			   oup[i]=isp[t].x; 
		   }
           for(int i=1;i<=ans;++i){
               out.print(oup[i]+" ");
           }
	   }
	    out.flush();
	    out.close();
	}
	
	static
    class AReader {
        private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        private StringTokenizer tokenizer = new StringTokenizer("");
        private String innerNextLine() {
            try {
                return reader.readLine();
            } catch (IOException ex) {
                return null;
            }
        }
        public boolean hasNext() {
            while (!tokenizer.hasMoreTokens()) {
                String nextLine = innerNextLine();
                if (nextLine == null) {
                    return false;
                }
                tokenizer = new StringTokenizer(nextLine);
            }
            return true;
        }
        public String nextLine() {
            tokenizer = new StringTokenizer("");
            return innerNextLine();
        }
        public String next() {
            hasNext();
            return tokenizer.nextToken();
        }
        public int nextInt() {
            return Integer.parseInt(next());
        }
 
        public long nextLong() {
            return Long.parseLong(next());
        }
 
    }
}

 

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值