CF 121D Lucky Segments (two points)

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove

题意:给出若干个区间,区间可以左右移动,所有区间移动幅度总和最多为K。问最多有多少个lucky number同时在n个区间中。

http://codeforces.com/contest/121/problem/D

感觉还不错的题,另外这周太水了,难得做个题。。。

首先处理出1e18以内的所有lucky number。

然后大致想法是two points处理lucky number的某个区间。

然后就是要check一下是否可行。

第一个条件是区间长度不能小于所有区间中最短的。。。

第二个条件是看所有区间能否移动到指定区间。

左右端点分开处理,对于左端点,如果目标为lucky[i],那么所有左端点 > lucky[i]的都必须移动过来。

排序后又是一次two points。右端点同样处理。

结束。。。注意下高精度

import java.util.*;
import java.io.*;
import java.lang.reflect.Array;
import java.math.*;
public class Main {
	public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        int t = 1;
        Task solver = new Task();
        while ((t --) > 0)
            solver.solve(in, out);
        out.close();
    }
}
class Task{
	static int N = 100005;
	static int M = (1 << 19) - 2;
	static long INF = 1000000000000000000L;
	long l[] = new long [N] , r[] = new long [N];
	long lucky[] = new long[M];
	BigInteger lsum[] = new BigInteger[M];
	BigInteger rsum[] = new BigInteger[M];
	void Init () {
		int c = 0;
		for (int i = 1 ; i <= 18 ; i ++) {
			for (int j = 0 ; j < (1 << i) ; j ++) {
				long t = 0;
				for (int k = 0 ; k < i ; k ++) {
					if ((j & (1 << k)) != 0)
						t = t * 10 + 7;
					else t = t * 10 + 4;
				}
				lucky[c ++] = t;
			}
		}
		Arrays.sort(lucky);
	}
	void solve (InputReader cin , PrintWriter cout) {
		Init ();
		int n = cin.nextInt();
		long k = cin.nextLong();
		long minlen = INF;
		for (int i = 0 ; i < n ; i ++) {
			l[i] = cin.nextLong();
			r[i] = cin.nextLong();
			minlen = Math.min(minlen, r[i] - l[i] + 1);
		}
		Arrays.sort(l , 0 , n);
		Arrays.sort(r , 0 , n);
		BigInteger sum = BigInteger.ZERO;
		for (int i = M - 1 , j = n - 1 ; i >= 0 ; i --) {
			while (j >= 0 && lucky[i] <= l[j]) {
				sum = sum.add (BigInteger.valueOf(l[j]));
				j --;
			}
			lsum[i] = sum.subtract(BigInteger.valueOf(n - j - 1).multiply(BigInteger.valueOf(lucky[i])));
		}
		sum = BigInteger.ZERO;
		for (int i = 0 , j = 0 ; i < M ; i ++) {
			while (j < n && r[j] <= lucky[i]) {
				sum = sum.add (BigInteger.valueOf(r[j]));
				j ++;
			}
			rsum[i] = BigInteger.valueOf(lucky[i]).multiply(BigInteger.valueOf(j)).subtract(sum);
		}
		int ans = 0;
		for (int i = 0 , j = 0 ; i < M ; i ++) {
            while (i > j || j < M && lucky[j] - lucky[i] + 1 <= minlen && lsum[i].add (rsum[j]).compareTo(BigInteger.valueOf(k)) <= 0) j ++;
            ans = Math.max (ans , j - i);
        }
		cout.println(ans);
	}
}
class InputReader {
    public BufferedReader reader;
    public StringTokenizer tokenizer;
    public InputReader(InputStream stream) {
        reader = new BufferedReader(new InputStreamReader(stream));
        tokenizer = null;
    }
    public String next() {
        while (tokenizer == null || !tokenizer.hasMoreTokens()) {
            try {
                tokenizer = new StringTokenizer(reader.readLine());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return tokenizer.nextToken();
    }
    public int nextInt() {
        return Integer.parseInt(next());
    }
    public long nextLong() {
    	return Long.parseLong(next());
    }
    public double nextDouble() {
    	return Double.parseDouble(next());
    }
    public BigInteger nextBigInteger() {
    	return new BigInteger(next());
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值