I.简单背包问题
题目大意
个物品,
次询问
- 问满足体积限制为
下,能得到的最大价值
解题思路
- 体积限制很大,数组开不下
- 询问次数很多,每次重做背包,时间不行
- 价值很小,最大价值总量为
- 考虑将价值放入状态,每次查询去找满足限制的最大价值
表示前
个物品得到
价值的最小体积
- 只用知道考虑完
个物品的结果,滚动掉一维
表示得到大于等于
价值所用的最小体积,即
的后缀最小值
- 对于每次询问,在
上二分查找
- 若
,则往右找还有更优解,反之,向左找
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.響符「パワーレゾナンス」
题目大意
解题思路
- 带修改的区间求和
区间查询
无法分解为区间操作
单点修改
只会变小,且
不变,可以答案标记进行去除,若区间上都有标记则直接跳过
- 由于单点修改,不同区间选取最终都视为对该点操作(在,则变;不在,则不变)
- 所以打标记的点可以用并查集维护(标记打过后,不会消去),进行缩点,减少遍历
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.小红构造数组
题目大意
- 给一个数
,求一个素数序列,满足其乘积为
,且序列中相邻两数不相同
- 不存在则输出-1
解题思路
- 对
进行素数拆分,统计每个素数个数
- 若有素数的个数大于总个数(总个数为奇数+1)的一半,则必有相邻两数相同,不存在
- 若无,则奇数偶数,依次隔一放一个
- 优化:先将素数
筛出,之后
可以直接跳过所有偶数,减少时间
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());
}
}
}