contest

google kickstart 2017 round B

Problem A. Math Encoder

Problem

Professor Math is working on a secret project and is facing a challenge where a list of numbers need to be encoded into a single number in the most efficient manner. After much research, Professor Math finds a 3 step process that can best encode the numbers:

The first step is to find all possible non-empty subsets of the list of numbers and then, for each subset, find the difference between the largest and smallest numbers (that is, the largest minus the smallest) in that subset. Note that if there is only one number in a subset, it is both the largest and the smallest number in that subset. The complete set itself is also considered a subset.
Then add up all the differences to get the final encoded number.
As the number may be large, output the number modulo 109 + 7 (1000000007).
The professor has shared an example and its explanation below. Given a list of numbers, can you help the professor build an efficient function to compute the final encoded number?

Input

The first line of the input gives the number of test cases, T. This is followed by T test cases where each test case is defined by 2 lines:

The first line gives a positive number N: the number of numbers in the list and
The second line contains a list of N positive integers Ki, sorted in non-decreasing order.
Output

For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y is the final encoded number.

Since the output can be a really big number, we only ask you to output the remainder of dividing the result by the prime 109 + 7 (1000000007).

Limits

1 ≤ T ≤ 25. 
1 ≤ Ki ≤ 10000, for all i.
Ki ≤ Ki+1, for all i < N - 1.
Small dataset

1 ≤ N ≤ 10.

Large dataset

1 ≤ N ≤ 10000.

Sample

Input 

1
4
3 6 7 9
     
Output 

Case #1: 44
View Code

题意: 给定一个集合,对该集合的每个子集的最大值和最小值之差求和。(包括自己)

解法:分别计算每个数作为最小值和最大值出现的次数,求和相减即可。对有序集合{a0,a1, a2....am }, ai作为最小值的次数为2^(m-i) ,作为最大值出现的次数为2^,复杂度:O(n). 可预先打表2的幂,注意溢出。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
const int N = 1e4 + 5;

int po[N];
int arr[N];
int n;

void precompute() {
    po[0] = 1;
    for(int i = 1 ; i < N ; i++) {
        po[i] = 2 * po[i-1] % MOD;
    }
}

int solve() {
    int ret = 0;
    for(int i = 0 ; i < n ; i++) {
            int temp = 1ll * (po[i] - po[n - 1 - i]) % MOD * arr[i] % MOD;
            ret = (ret + temp) % MOD;
    }

    if(ret < 0) ret += MOD;
    return ret;
}

int main() {
    precompute();
        freopen("A-large.in", "r", stdin);
        freopen("A-small.out", "w", stdout);
    int t; cin >> t;
    for(int tc = 1 ; tc <= t ; tc++) {
              scanf("%d", &n);
      for(int i = 0 ; i < n ; i++)
          scanf("%d", arr + i);
        int ret = solve();
        printf("Case #%d: %d\n", tc, ret);
                fprintf(stderr, "Case #%d processed\n", tc);
    }
    return 0;
}
View Code

 Problem B. Center

Problem

There are N weighted points in a plane. Point i is at (Xi, Yi) and has weight Wi.

In this problem, we need to find a special center of these points. The center is a point (X, Y) such that the sum of max(|X-Xi|, |Y-Yi|)*Wi is minimum.

Input

The input starts with one line containing exactly one integer T, which is the number of test cases. T test cases follow.

Each test case begins with one line containing one integer N. N lines follow. Each line contains three space-separated real numbers Xi, Yi, and Wi. Xi, Yi and Wi have exactly 2 digits after the decimal point.

Output

For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y is the sum of max(|X-Xi|, |Y-Yi|)*Wi for center (X, Y).

y will be considered correct if it is within an absolute or relative error of 10-6 of the correct answer. See the FAQ for an explanation of what that means, and what formats of real numbers we accept.

Limits

1 ≤ T ≤ 10.
-1000.00 ≤ Xi ≤ 1000.00.
-1000.00 ≤ Yi ≤ 1000.00.
Small dataset

1 ≤ N ≤ 100;
Wi = 1.0, for all i.
Large dataset

1 ≤ N ≤ 10000;
1.0 ≤ Wi ≤ 1000.0, for all i.
Sample
Input 
3
2
0.00 0.00 1.00
1.00 0.00 1.00
4
1.00 1.00 1.00
1.00 -1.00 1.00
-1.00 1.00 1.00
-1.00 -1.00 1.00
2
0.00 0.00 1.00
1.00 0.00 2.00
     
Output 

Case #1: 1.0
Case #2: 4.0
Case #3: 1.0
View Code

题意:平面上有一堆(xi,yi) ,每个点有着不同的权重w, 求使得sum max(|X-Xi|, |Y-Yi|)*Wi 最小的点(x,y),输出最小的和。

解法:1:

AtCoder Regular 074

2017.05.20 link: http://arc074.contest.atcoder.jp/

C chocolate bar

 

C - Chocolate Bar
Time limit : 2sec / Memory limit : 256MB

Score : 400 points

Problem Statement
There is a bar of chocolate with a height of H blocks and a width of W blocks. Snuke is dividing this bar into exactly three pieces. He can only cut the bar along borders of blocks, and the shape of each piece must be a rectangle.

Snuke is trying to divide the bar as evenly as possible. More specifically, he is trying to minimize Smax - Smin, where Smax is the area (the number of blocks contained) of the largest piece, and Smin is the area of the smallest piece. Find the minimum possible value of Smax−Smin.

Constraints
2≤H,W≤105
Input
Input is given from Standard Input in the following format:

H W
Output
Print the minimum possible value of Smax−Smin.

Sample Input 1
3 5
Sample Output 1
0

Sample Input 2
4 5
Sample Output 2
2

Sample Input 3
5 5
Sample Output 3
4

Sample Input 4
100000 2
Sample Output 4
1

Sample Input 5
100000 100000
Sample Output 5
50000
View Code

 

题意: m * n矩阵切两刀分成三份使得面积最大最小值差别最小。

这个题。。。。直接暴力分每一刀就得了。。。我居然想了一整场的规律,啊?。。。 看得我想死。。。有点菜鸡得过分了吧??。。

#include <bits/stdc++.h>
using namespace std;
typedef long long lint;
typedef pair<int, int> pi;
const int mod = 1e9 + 7;
 
lint n, m;
 
int main(){
    cin >> n >> m;
    lint ret = 1e18;
    for(int i=1; i<n; i++){
        lint w1 = i * m;
        lint w2 = max(((n - i) / 2) * m, (n - i) * (m / 2));
        lint w3 = (n - i) * m - w2;
        vector<lint> v = {w1, w2, w3};
        sort(v.begin(), v.end());
        ret = min(ret, v[2] - v[0]);
    }
    swap(n, m);
    for(int i=1; i<n; i++){
        lint w1 = i * m;
        lint w2 = max(((n - i) / 2) * m, (n - i) * (m / 2));
        lint w3 = (n - i) * m - w2;
        vector<lint> v = {w1, w2, w3};
        sort(v.begin(), v.end());
        ret = min(ret, v[2] - v[0]);
    }
    cout << ret << endl;
}
View Code

D 3N Numbers

D - 3N Numbers
Time limit : 2sec / Memory limit : 256MB

Score : 500 points

Problem Statement
Let N be a positive integer.

There is a numerical sequence of length 3N, a=(a1,a2,…,a3N). Snuke is constructing a new sequence of length 2N, a', by removing exactly N elements from a without changing the order of the remaining elements. Here, the score of a' is defined as follows: (the sum of the elements in the first half of a')−(the sum of the elements in the second half of a').

Find the maximum possible score of a'.

Constraints
1≤N≤105
ai is an integer.
1≤ai≤109
Partial Score
In the test set worth 300 points, N≤1000.
Input
Input is given from Standard Input in the following format:

N
a1 a2 … a3N
Output
Print the maximum possible score of a'.

Sample Input 1
2
3 1 4 1 5 9
Sample Output 1
1
When a2 and a6 are removed, a' will be (3,4,1,5), which has a score of (3+4)−(1+5)=1.

Sample Input 2
1
1 2 3
Sample Output 2
-1
For example, when a1 are removed, a' will be (2,3), which has a score of 2−3=−1.

Sample Input 3
3
8 2 2 7 4 6 5 3 8
Sample Output 3
5
For example, when a2, a3 and a9 are removed, a' will be (8,7,4,6,5,3), which has a score of (8+7+4)−(6+5+3)=5.
View Code

题意:从3N的数组中选2N个数, max{前N个之和 - 后N个之和}。 用两个优先级队列分别表示从1- i中前 n个和的最大值, i+1 - 3n中选后n个和的最小值,最后跑一遍即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long lint;
typedef pair<int, int> pi;
const int mod = 1e9 + 7;
 
int n, a[300005];
lint l[300005], r[300005];
 
int main(){
    scanf("%d",&n);
    for(int i=1; i<=3*n; i++) scanf("%d",&a[i]);
    priority_queue<int, vector<int>, greater<int> > pq;
    priority_queue<int> pq2;
    lint sum = 0;
    for(int i=1; i<=3*n; i++){
        sum += a[i];
        pq.push(a[i]);
        while(pq.size() > n){
            sum -= pq.top();
            pq.pop();
        }
        l[i] = sum;
    }
    sum = 0;
    for(int i=3*n; i; i--){
        sum += a[i];
        pq2.push(a[i]);
        while(pq2.size() > n){
            sum -= pq2.top();
            pq2.pop();
        }
        r[i] = sum;
    }
    lint ret = -1e18;
    for(int i=n; i<=2*n; i++){
        ret = max(ret, l[i] - r[i+1]);
    }
    cout << ret << endl;
}
View Code

E, F。。。。 没做。。。待补。。。

总结:有点菜啊??。。。。不如去参加beginner吧。。。而且参加了beginner也不能拿满分啊???。。。。

 

hihoCoder [Offer收割]编程练习赛17

2017.05.21 link:http://www.hihocoder.com/contest/offers17

A F1 score 

F1 Score
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
小Hi和他的小伙伴们一起写了很多代码。时间一久有些代码究竟是不是自己写的,小Hi也分辨不出来了。

于是他实现了一个分类算法,希望用机器学习实现自动分类。

为了评价这个分类算法的优劣,他选出了N份有标记的代码作测试集,并决定用F1 Score作为评价标准。

给出N份代码的实际作者是不是小Hi以及分类算法预测的结果,请你计算F1 Score。

输入
第一行包含一个整数N。(1 <= N <= 1000)    

以下N行每行包含两个字符(+或-)。第一个字符代表这份代码的实际作者是不是小Hi(+代表是,-代表不是),第二个代表预测的作者是不是小Hi(+代表是,-代表不是)。  

输出
一个百分数,X%,代表答案,X保留两位小数。
View Code

 直接按F1的定义求即可,似乎不需要对0/0 特判。

#include<bits/stdc++.h>
using namespace std;
int main(){
  ios::sync_with_stdio(0);
  cin.tie(0);
  int n;
  cin >> n;
  int tp = 0;
  int fp = 0;
  int tn = 0;
  int fn = 0;
  for (int i = 0; i < n; i++) {
   char temp1, temp2;
   cin >> temp1 >> temp2;
   if (temp1 == '+' && temp2 == '+') {
      tp++;
    } else if (temp1 == '+' && temp2 == '-') {
      tn++;
    } else if (temp1 == '-' && temp2 == '+') {
      fp++;
    } else {
      fn++;
    }
  }
  printf("%.2f%\n", 100 * 2.0 * tp / (tp * 2 + fp + tn));
  return 0;
}
View Code

B 数组重排

数组重排2
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一个1-N的排列A1, A2, ... AN,每次操作小Hi可以选择一个数,把它放到数组的最左边。

请计算小Hi最少进行几次操作就能使得新数组是递增排列的。

输入
第一行包含一个整数N。

第二行包含N个两两不同整数A1, A2, ... AN。(1 <= Ai <= N)

对于60%的数据 1 <= N <= 20

对于100%的数据 1 <= N <= 100000

输出
一个整数代表答案

样例输入
5
2 3 1 4 5
样例输出
1
View Code

每次移动一个数到数组最左边,求最少的移动次数使得数组递增。 实为从尾部往前看,查找一个最大数开始的递减子序列,此序列内的数不需要换,其他的要换。

#include <bits/stdc++.h>
using namespace std;
const int LEN = 100000 + 10;
int n, num[LEN], snum[LEN];

int main()
{
    while(cin >> n) {
        for(int i=0; i<n; i++) {
            cin >> num[i];
            snum[i] = num[i];
        }
        sort(snum, snum + n);
        int ans = n;
        for(int i=n-1, j=n-1; i>=0; i--) {
            if(num[i] == snum[j]) {
                j --;
                ans --;
            }
        }
        cout << ans << endl;
    }
    return 0;
}
View Code

这题其实可以写得更简单,由于数组里的值比较特殊,1-n各出现一次所以递减序列一定是n, n - 1, n - 2.... 令ans 为n, 每次a[i] = ans时ans--匹配下一个即可。

ans = n
for (i = n - 1 : 1 : 0) {
    if ( a[i] == ans) {
        ans--;
    }
}
View Code

C 逆序对

逆序对
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一个1-N的排列A1, A2, ... AN,如果Ai和Aj满足i < j且Ai > Aj,我们就称(Ai, Aj)是一个逆序对。  

求A1, A2 ... AN中所有逆序对的数目。  

输入
第一行包含一个整数N。  

第二行包含N个两两不同整数A1, A2, ... AN。(1 <= Ai <= N)  

对于60%的数据 1 <= N <= 1000  

对于100%的数据 1 <= N <= 100000

输出
一个整数代表答案

样例输入
5
3 2 4 5 1
样例输出
5
View Code

按照分治的方法查找即可,手写了一个归并排序,每次合并两个数组时前面数组有大于后面数组的更新即可。

#include<bits/stdc++.h>
using namespace std;
int a[100005];
int temp[100005];
long long  ans = 0;

void Merge(int lo,int mid, int hi) {
  int i = lo;
  int j = mid + 1;
  int cur = 0;
  while (i <= mid && j <= hi) {
    if (a[i] < a[j]) {
      temp[cur++] = a[i++];
    } else {
      temp[cur++] = a[j++];
      ans += mid - i + 1;
    }
  }
  while (i <= mid) {
    temp[cur++] = a[i++];
  }
  while (j <= hi) {
    temp[cur++] = a[j++];
  }
  for (int k = 0; k < cur; k++) {
    a[lo++] = temp[k];
  }
}
void mergesort(int lo, int hi) {
  if (lo == hi) {
    return;
  }
  int mid = (hi + lo) / 2;
  mergesort(lo, mid);
  mergesort(mid + 1, hi);
  Merge(lo, mid, hi);
}
int main(){
  ios::sync_with_stdio(0);
  cin.tie(0);
  int n;
  cin >> n;
  for (int i = 0; i < n; i++) {
    cin >> a[i];
  }
  mergesort(0, n - 1);
  cout << ans <<"\n";
  return 0;
}
View Code

D 逃离迷宫3

 逃离迷宫3
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
小Hi被坏女巫抓进一座由无限多个格子组成的矩阵迷宫。

小Hi一开始处于迷宫中央(0, 0)的位置。他发现每个格子都印有一个大写字母。并且从(0, 0)开始,按照A-Z的顺序,沿着顺时针螺旋循环排列,如下图所示(向右是X正方向,向上是Y正方向):

          0
         ...
      CXYZABCDE
      BWZABCDEF
      AVYJKLMFG
      ZUXIBCNGH
0  ...YTWHADOHI...
      XSVGFEPIJ
      WRUTSRQJK
      VQPONMLKL
      UTSRQPONM
         ... 
小Hi发现每次他可以移动到上下左右相邻的格子中,但是代价是心智受到1点伤害。此外他还可以移动到印有相同字母的格子中,无论两个格子相距多远,代价也是心智受到1点伤害。

给定迷宫出口的位置(X, Y),小Hi想知道离开迷宫最少受到多少点伤害。  

输入
第一行包含一个整数N,表示测试数据的组数。(1 <= N <= 12)  

以下N行每行包含两个整数X和Y,代表出口位置。  

对于30%的数据,-100 <= X, Y <= 100    

对于100%的数据, -1000000 <= X, Y <= 1000000

输出
对于每组数据输出一个整数表示答案。 每组数据单独一行。

样例输入
3  
1 2
-4 2  
4 1
样例输出
3  
1  
2
View Code

没做出来。。。待补

感觉是先计算出A到每个字符的最短距离,然后判断该坐标是哪个字符。。。

总结:睡醒的时候比赛都开始了十几分钟了啊?。。。状态不好,C题第一次提交只得70分还以为归并写错了,瞎敲了一堆测试例子好像在浪费时间啊?。。后来才想到结果溢出了,用ll即可。B题这么显然的思路居然想了这么久啊。。。丢脸,得多努力。。。。

 AtCoder Grand 015

2017.05.27 link: http://agc015.contest.atcoder.jp/

A A+...B

A - A+...+B Problem
Time limit : 2sec / Memory limit : 256MB

Score : 200 points

Problem Statement
Snuke has N integers. Among them, the smallest is A, and the largest is B. We are interested in the sum of those N integers. How many different possible sums there are?

Constraints
1≤N,A,B≤109
A and B are integers.

Input
Input is given from Standard Input in the following format:

N A B
Output
Print the number of the different possible sums.

Sample Input 1
4 4 6
Sample Output 1
5
There are five possible sums: 18=4+4+4+6, 19=4+4+5+6, 20=4+5+5+6, 21=4+5+6+6 and 22=4+6+6+6.

Sample Input 2
5 4 3
Sample Output 2
0
Sample Input 3
1 7 10
Sample Output 3
0
Sample Input 4
1 3 3
Sample Output 4
1
View Code

很显然, 结果为b + (n - 1)a 到 a + (n - 1) b 之间.

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    std::ios::sync_with_stdio(false);
    ll n, m ,k;
    cin >> n >> m >> k;
    cout << max((ll)0, (n - 2) * (k - m) + 1) << "\n";
    return 0;
}
View Code

B evilator

B - Evilator
Time limit : 2sec / Memory limit : 256MB

Score : 400 points

Problem Statement
Skenu constructed a building that has N floors. The building has an elevator that stops at every floor.

There are buttons to control the elevator, but Skenu thoughtlessly installed only one button on each floor - up or down. This means that, from each floor, one can only go in one direction. If Si is U, only "up" button is installed on the i-th floor and one can only go up; if Si is D, only "down" button is installed on the i-th floor and one can only go down.

The residents have no choice but to go to their destination floors via other floors if necessary. Find the sum of the following numbers over all ordered pairs of two floors (i,j): the minimum number of times one needs to take the elevator to get to the j-th floor from the i-th floor.

Constraints
2≤|S|≤105
Si is either U or D.
S1 is U.
S|S| is D.
Input
The input is given from Standard Input in the following format:

S1S2…S|S|
Output
Print the sum of the following numbers over all ordered pairs of two floors (i,j): the minimum number of times one needs to take the elevator to get to the j-th floor from the i-th floor.

Sample Input 1
UUD
Sample Output 1
7
From the 1-st floor, one can get to the 2-nd floor by taking the elevator once.

From the 1-st floor, one can get to the 3-rd floor by taking the elevator once.

From the 2-nd floor, one can get to the 1-st floor by taking the elevator twice.

From the 2-nd floor, one can get to the 3-rd floor by taking the elevator once.

From the 3-rd floor, one can get to the 1-st floor by taking the elevator once.

From the 3-rd floor, one can get to the 2-nd floor by taking the elevator once.

The sum of these numbers of times, 7, should be printed.

Sample Input 2
UUDUUDUD
Sample Output 2
77
View Code

很显然,与当前方向一致的只需要一次,不一致的需要两次。

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    std::ios::sync_with_stdio(false);
    string s;
    cin >> s;
    int l = s.length();
    ll ans = 0;
    for (int i = 0; i < l; i++) {
        if (s[i] == 'U') {
            ans += -1L + l - i + 2 * i;
        } else {
            ans += 0L + i + 2 * (l - 1 - i);
        }
    }
    cout << ans << endl;
    return 0;
}
View Code

 C nuske vs Phantom Thnook

C - Nuske vs Phantom Thnook
Time limit : 4sec / Memory limit : 256MB

Score : 700 points

Problem Statement
Nuske has a grid with N rows and M columns of squares. The rows are numbered 1 through N from top to bottom, and the columns are numbered 1 through M from left to right. Each square in the grid is painted in either blue or white. If Si,j is 1, the square at the i-th row and j-th column is blue; if Si,j is 0, the square is white. For every pair of two blue square a and b, there is at most one path that starts from a, repeatedly proceeds to an adjacent (side by side) blue square and finally reaches b, without traversing the same square more than once.

Phantom Thnook, Nuske's eternal rival, gives Q queries to Nuske. The i-th query consists of four integers xi,1, yi,1, xi,2 and yi,2 and asks him the following: when the rectangular region of the grid bounded by (and including) the xi,1-th row, xi,2-th row, yi,1-th column and yi,2-th column is cut out, how many connected components consisting of blue squares there are in the region?

Process all the queries.

Constraints
1≤N,M≤2000
1≤Q≤200000
Si,j is either 0 or 1.
Si,j satisfies the condition explained in the statement.
1≤xi,1≤xi,2≤N(1≤i≤Q)
1≤yi,1≤yi,2≤M(1≤i≤Q)
Input
The input is given from Standard Input in the following format:

N M Q
S1,1..S1,M
:
SN,1..SN,M
x1,1 yi,1 xi,2 yi,2
:
xQ,1 yQ,1 xQ,2 yQ,2
Output
For each query, print the number of the connected components consisting of blue squares in the region.

Sample Input 1
Copy
3 4 4
1101
0110
1101
1 1 3 4
1 1 3 1
2 2 3 4
1 2 2 4
Sample Output 1
Copy
3
2
2
2


In the first query, the whole grid is specified. There are three components consisting of blue squares, and thus 3 should be printed.

In the second query, the region within the red frame is specified. There are two components consisting of blue squares, and thus 2 should be printed. Note that squares that belong to the same component in the original grid may belong to different components.

Sample Input 2
Copy
5 5 6
11010
01110
10101
11101
01010
1 1 5 5
1 2 4 5
2 3 3 4
3 3 3 3
3 1 3 5
1 1 3 4
Sample Output 2
3
2
1
1
3
2
View Code

题意: 矩阵内有一些蓝色点,所有蓝色点形成一个森林求给定区域内的联通分量个数。

思路:联通分量个数即为蓝色块的个数减去相邻的块的个数(也就是相邻边的个数),所以预处理(1,1)到(x,y)的蓝色点个数以及相邻边数即可。(O(n2))。

注意预处理相邻边数时,分成横边和竖边分别计算。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char s[2005][2005];
int nodes[2005][2005];
int x_edges[2005][2005];
int y_edges[2005][2005];
void gao(int arr[2005][2005], int i, int j) {
    arr[i][j] = arr[i - 1][j] + arr[i][j - 1] - arr[i - 1][ j - 1];
}
int gao2(int arr[2005][2005], int x1, int y1, int x2, int y2) {
    return arr[x2][y2] - arr[x1 - 1][y2] - arr[x2][y1 - 1] + arr[x1 - 1][y1 - 1];;
}
int main() {
    int n, m, q;
    std::ios::sync_with_stdio(false);
    cin >> n >> m >> q;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cin >> s[i][j];
            gao(nodes, i, j);
            gao(x_edges, i , j);
            gao(y_edges, i, j);
            if (s[i][j] == '1') {
                nodes[i][j]++;
                if (s[i - 1][j] == '1') {
                    x_edges[i][j]++;
                }
                if (s[i][j - 1] == '1') {
                    y_edges[i][j]++;
                }
            }
        }
    }
    while (q--) {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        int ans = gao2(nodes, x1, y1, x2, y2);
        ans -= gao2(x_edges, x1 + 1, y1, x2, y2);
        ans -= gao2(y_edges, x1, y1 + 1, x2, y2);
        cout << ans << "\n";
    }
    return 0;
}
View Code

D A or.... B

D - A or...or B Problem
Time limit : 2sec / Memory limit : 256MB

Score : 900 points

Problem Statement
Nukes has an integer that can be represented as the bitwise OR of one or more integers between A and B (inclusive). How many possible candidates of the value of Nukes's integer there are?

Constraints
1≤A≤B<260
A and B are integers.
Input
The input is given from Standard Input in the following format:

A
B
Output
Print the number of possible candidates of the value of Nukes's integer.

Sample Input 1
Copy
7
9
Sample Output 1
Copy
4
In this case, A=7 and B=9. There are four integers that can be represented as the bitwise OR of a non-empty subset of {7, 8, 9}: 7, 8, 9 and 15.

Sample Input 2
Copy
65
98
Sample Output 2
Copy
63
Sample Input 3
Copy
271828182845904523
314159265358979323
Sample Output 3
Copy
68833183630578410
View Code

题意:对A到B之间的任意多个数进行二进制或,求结果集的大小。注意可以自己和自己或。

题解:很显然应该考虑A, B的二进制, 对于A, B前n个相同的位数,很显然对结果没有影响,可以删去。

设第一位不一样的为第r位。 B  > A 所以 Br = 1 Ar = 0, 将[A, B] 分为[A, 2r), [2r, B]。设B中第r位之后第一次非0的位数为k。

若只从[A, 2r)取数,则最小值为A(因为每次或之后1的次数不可能减少,所以数只能更大),最大值为2r - 1(或了所有值)。且之间所有的值都能取到。(自己或自己即可)

若只从 [2r, B]取数,则同理范围为[2r, 2r + 2k + 1 - 1] (To do:证明连续)

若两边各取一个,则同理范围为[A + 2r, 2r + 1 - 1]。(取最小的两个, 所有的都为一)。

取上述区间的并集即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
    std::ios::sync_with_stdio(false);
    ll a, b;
    cin >> a >> b;
    if (a == b) {
        cout << "1\n";
        return 0;
    }
    ll r = 60;
    while ((a & (1LL << r)) == (b & (1LL << r))) {
        r--;
    }
    a &= (1LL << (r + 1)) - 1;
    b &= (1LL << (r + 1)) - 1;
    ll k = r - 1;
    while (k >= 0 && ((1LL << k) & b) == 0) {
        k--;
    }
    ll ans = (1LL << (r + 1)) - a;
    if (a > (1LL << (k + 1))) {
        ans -= a - (1LL << (k + 1));
    }
    cout << ans << "\n";
    return 0;
}
View Code

总结:菜啊,没见过的题就不会啊。。。???太过拟合了吧啊???。。。。C居然想着对每个查询做并查集啊?????。。。时间复杂度肯定不够啊???。。就算走投无路也不能选择吃屎自杀吧啊???

AtCoder Regular 075

C Bugged

C - Bugged
Time limit : 2sec / Memory limit : 256MB

Score : 300 points

Problem Statement
You are taking a computer-based examination. The examination consists of N questions, and the score allocated to the i-th question is si. Your answer to each question will be judged as either "correct" or "incorrect", and your grade will be the sum of the points allocated to questions that are answered correctly. When you finish answering the questions, your answers will be immediately judged and your grade will be displayed... if everything goes well.

However, the examination system is actually flawed, and if your grade is a multiple of 10, the system displays 0 as your grade. Otherwise, your grade is displayed correctly. In this situation, what is the maximum value that can be displayed as your grade?

Constraints
All input values are integers.
1≤N≤100
1≤si≤100
Input
Input is given from Standard Input in the following format:

N
s1
s2
:
sN
Output
Print the maximum value that can be displayed as your grade.

Sample Input 1
3
5
10
15
Sample Output 1
25
Your grade will be 25 if the 10-point and 15-point questions are answered correctly and the 5-point question is not, and this grade will be displayed correctly. Your grade will become 30 if the 5-point question is also answered correctly, but this grade will be incorrectly displayed as 0.

Sample Input 2
3
10
10
15
Sample Output 2
35
Your grade will be 35 if all the questions are answered correctly, and this grade will be displayed correctly.

Sample Input 3
3
10
20
30
Sample Output 3
0
Regardless of whether each question is answered correctly or not, your grade will be a multiple of 10 and displayed as 0.
View Code

题意:一组正数,对数组若干元素求和,最后的和为10的倍数是会变成0.求最大的和。

题解:对所有求和,若和为10的倍数,则升序排序,减去最小的非10倍数的值。注意所有都为10的倍数时。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[105];
int main() {
    std::ios::sync_with_stdio(false);
    int n;
    cin >> n;
    int ans = 0;
    for (int i =0; i < n; i++) {
        cin >> a[i];
        ans += a[i];
    }
    sort(a, a + n);
    int index = 0;
    while (index < n && ans % 10 == 0) {
        if (a[index] % 10 != 0) {
            ans -= a[index];
        }
        index++;
    }
    //cout << ans << endl;
    cout << ((ans % 10 == 0) ? 0 : ans) << "\n";
    return 0;
}
View Code

D Widespread

D - Widespread
Time limit : 2sec / Memory limit : 256MB

Score : 400 points

Problem Statement
You are going out for a walk, when you suddenly encounter N monsters. Each monster has a parameter called health, and the health of the i-th monster is hi at the moment of encounter. A monster will vanish immediately when its health drops to 0 or below.

Fortunately, you are a skilled magician, capable of causing explosions that damage monsters. In one explosion, you can damage monsters as follows:

Select an alive monster, and cause an explosion centered at that monster. The health of the monster at the center of the explosion will decrease by A, and the health of each of the other monsters will decrease by B. Here, A and B are predetermined parameters, and A>B holds.
At least how many explosions do you need to cause in order to vanish all the monsters?

Constraints
All input values are integers.
1≤N≤105
1≤B<A≤109
1≤hi≤109
Input
Input is given from Standard Input in the following format:

N A B
h1
h2
:
hN
Output
Print the minimum number of explosions that needs to be caused in order to vanish all the monsters.

Sample Input 1
Copy
4 5 3
8
7
4
2
Sample Output 1
2
You can vanish all the monsters in two explosion, as follows:

First, cause an explosion centered at the monster with 8 health. The healths of the four monsters become 3, 4, 1 and −1, respectively, and the last monster vanishes.
Second, cause an explosion centered at the monster with 4 health remaining. The healths of the three remaining monsters become 0, −1 and −2, respectively, and all the monsters are now vanished.
Sample Input 2
2 10 4
20
20
Sample Output 2
4
You need to cause two explosions centered at each monster, for a total of four.

Sample Input 3
5 2 1
900000000
900000000
1000000000
1000000000
1000000000
Sample Output 3
800000000
View Code

题意:有一堆怪物N,已知每只的初始生命,每次射击能对一个怪物造成A的伤害,其余的造成伤害B。求最小次数击毙所有怪物。

题解:对击毙次数二分即可。统计每个怪物需要直接射击的次数和,若结果大于假定的次数,则增大即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll h[100005];
ll n, a, b;
bool valid (ll k) {
  ll temp = 0;
   for (int i = 0; i < n; i++) {
     if (b * k < h[i]) {
        temp += (h[i] - k * b + a - b - 1) / (a - b);
     }
  }
  return temp <= k;
}
int main() {
  cin >> n >> a >> b;
  for (int i = 0; i < n; i++) {
    cin >> h[i];
  }
  ll lo = 0, hi = 1e9;
  ll mid;
  while (lo < hi - 1) {
     mid = (lo + hi) / 2;
     if (valid(mid)) {
        hi = mid;
     } else {
       lo = mid;
     }
  }
  cout << hi << endl;
  //cout << lo << " " << mid << " " << hi << endl;
  return 0;
}
View Code

tips: 注意while 的循环条件, 最后输出是hi还是lo(upper_bound lower_bound)

 E Meaningful Mean

E - Meaningful Mean
Time limit : 2sec / Memory limit : 256MB

Score : 600 points

Problem Statement
You are given an integer sequence of length N, a= {a1,a2,…,aN}, and an integer K.

a has N(N+1)⁄2 non-empty contiguous subsequences, {al,al+1,…,ar} (1≤l≤r≤N). Among them, how many have an arithmetic mean that is greater than or equal to K?

Constraints
All input values are integers.
1≤N≤2×105
1≤K≤109
1≤ai≤109
Input
Input is given from Standard Input in the following format:

N K
a1
a2
:
aN
Output
Print the number of the non-empty contiguous subsequences with an arithmetic mean that is greater than or equal to K.

Sample Input 1
3 6
7
5
7
Sample Output 1
5
All the non-empty contiguous subsequences of a are listed below:

{a1} = {7}
{a1,a2} = {7,5}
{a1,a2,a3} = {7,5,7}
{a2} = {5}
{a2,a3} = {5,7}
{a3} = {7}
Their means are 7, 6, 193, 5, 6 and 7, respectively, and five among them are 6 or greater. Note that {a1} and {a3} are indistinguishable by the values of their elements, but we count them individually.

Sample Input 2
1 2
1
Sample Output 2
0
Sample Input 3
7 26
10
20
30
40
30
20
10
Sample Output 3
13
View Code

题意:求平均值大于等于K的连续子序列数。

题解:考虑l到r的序列: $\sum_{i=l}^{r}a_i>=(r + 1 - l)*K$ 

将序列求和裂成sum{0 - r} - sum{0 - l} =>   $\sum_{i=0}^{r}a_i - (r + 1) * K >= \sum_{i=0}^{l}a_i - l*K$ 

即新建数列b:$b_n = \sum_{i=0}^{n - 1}a_i - n * K$ 

所求结果即为数列b中顺序对的个数。方法与逆序对求法一致,分治(归并)或树状数组即可。

分治:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ans = 0;
void mergesort(vector<ll> & b, int lo, int hi) {
    if (lo >= hi) {
        return;
    }
    int mid = (lo + hi) / 2;
    mergesort(b, lo, mid);
    mergesort(b, mid + 1, hi);
    vector <ll> temp;
    int i = lo, j = mid + 1;
    while (i <= mid && j <= hi) {
        if (b[i] <= b[j]) { // big to small
            temp.push_back(b[j++]);
            ans += mid - i + 1;
        } else {
            temp.push_back(b[i++]);
        }
    }
    while (i <= mid) {
        temp.push_back(b[i++]);
    }
    while (j <= hi) {
        temp.push_back(b[j++]);
    }
    for (int k = 0; k < hi - lo + 1; k++) {
        b[lo + k] = temp[k];
    }
}
int main() {
    std::ios::sync_with_stdio(false);
    int n, k;
    cin >> n >> k;
    vector <ll> b(n + 1);
    ll temp;
    b[0] = 0;
    for (int i = 1; i <= n; i++) {
        cin >> temp;
        b[i] = b[i - 1] + temp -k;
    }
    mergesort(b, 0, n);
    cout << ans << endl;
    return 0;
}
View Code

下面用树状数组:

除了数列b外,新建数组表示每个数出现的次数,对于当前的数$b_i$要求的结果即为 之前小于$b_i$的个数。即sum(b[i]),然后将add(b[i], 1)将b[i]出现次数加一即可。

 

F待补。。

总结:行吧。。。二分不会,E转换成新数列也不会。。。

AtCoder Regular 076

2017.6.24 

C Reconciled?

C - Reconciled?
Time limit : 2sec / Memory limit : 256MB

Score : 300 points

Problem Statement
Snuke has N dogs and M monkeys. He wants them to line up in a row.

As a Japanese saying goes, these dogs and monkeys are on bad terms. ("ken'en no naka", literally "the relationship of dogs and monkeys", means a relationship of mutual hatred.) Snuke is trying to reconsile them, by arranging the animals so that there are neither two adjacent dogs nor two adjacent monkeys.

How many such arrangements there are? Find the count modulo 109+7 (since animals cannot understand numbers larger than that). Here, dogs and monkeys are both distinguishable. Also, two arrangements that result from reversing each other are distinguished.

Constraints
1≤N,M≤105
Input
Input is given from Standard Input in the following format:

N M
Output
Print the number of possible arrangements, modulo 109+7.

Sample Input 1
Copy
2 2
Sample Output 1
8
We will denote the dogs by A and B, and the monkeys by C and D. There are eight possible arrangements: ACBD, ADBC, BCAD, BDAC, CADB, CBDA, DACB and DBCA.

Sample Input 2
3 2
Sample Output 2
12
Sample Input 3
1 8
Sample Output 3
0
Sample Input 4
100000 100000
Sample Output 4
530123477
View Code

题意:N只狗M个猴子作成一排,两只狗或两只猴子不能连续坐,求符合要求的排列的个数。

题解:直接排列公式即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
int main()
{
    ll a, b, n, m;
    cin >> n >> m;
    a = max(n, m);
    b = min(n, m);
    if (a - b > 1) {
        cout << 0 << "\n";
        return 0;
    }
    ll ans = 1;
    if (a == b) {
        ans = 2;
        for (int i = a; i >= 1; i--) {
            ans = ans * i % mod * i % mod;
        }
    } else {
        ans = a;
        for (int i = b; i >= 1; i--) {
            ans = ans * i % mod * i % mod;
        }
    }
    cout << ans << "\n";
    return 0;
}
View Code

D built?

Time limit : 2sec / Memory limit : 256MB

Score : 500 points

Problem Statement
There are N towns on a plane. The i-th town is located at the coordinates (xi,yi). There may be more than one town at the same coordinates.

You can build a road between two towns at coordinates (a,b) and (c,d) for a cost of min(|a−c|,|b−d|) yen (the currency of Japan). It is not possible to build other types of roads.

Your objective is to build roads so that it will be possible to travel between every pair of towns by traversing roads. At least how much money is necessary to achieve this?

Constraints
2≤N≤105
0≤xi,yi≤109
All input values are integers.
Input
Input is given from Standard Input in the following format:

N
x1 y1
x2 y2
:
xN yN
Output
Print the minimum necessary amount of money in order to build roads so that it will be possible to travel between every pair of towns by traversing roads.

Sample Input 1
3
1 5
3 9
7 8
Sample Output 1
3
Build a road between Towns 1 and 2, and another between Towns 2 and 3. The total cost is 2+1=3 yen.

Sample Input 2
6
8 3
4 9
12 19
18 1
13 5
7 6
Sample Output 2
8
View Code

题意:已知N座城市的左边(x,y), 两座城市之间修路的消耗为min(|x1 - x2|, |y1 - y2|),求使城市互通的最低消耗。

题解:每两个城市之间建两条边|x1 - x2|, |y1 - y2|,然后跑最小生成树即可。

 

google kickstart 2017 round D

https://codejam.withgoogle.com/codejam/contest/8284487/dashboard

A Go Sightseeing

Problem

When you travel, you like to spend time sightseeing in as many cities as possible, but sometimes you might not be able to because you need to catch the bus to the next city. To maximize your travel enjoyment, you decide to write a program to optimize your schedule.

You begin at city 1 at time 0 and plan to travel to cities 2 to N in ascending order, visiting every city. There is a bus service from every city i to the next city i + 1. The i-th bus service runs on a schedule that is specified by 3 integers: Si, Fi and Di, the start time, frequency and ride duration. Formally, this means that there is a bus leaving from city i at all times Si + xFi, where x is an integer and x ≥ 0, and the bus takes Di time to reach city i + 1.

At each city between 1 and N - 1, inclusive, you can decide to spend Ts time sightseeing before waiting for the next bus, or you can immediately wait for the next bus. You cannot go sightseeing multiple times in the same city. You may assume that boarding and leaving buses takes no time. You must arrive at city N by time Tf at the latest. (Note that you cannot go sightseeing in city N, even if you arrive early. There's nothing to see there!)

What is the maximum number of cities you can go sightseeing in?

Input

The input starts with one line containing one integer T, which is the number of test cases. T test cases follow.

Each test case begins with a line containing 3 integers, N, Ts and Tf, representing the number of cities, the time taken for sightseeing in any city, and the latest time you can arrive in city N.

This is followed by N - 1 lines. On the i-th line, there are 3 integers, Si, Fi and Di, indicating the start time, frequency, and duration of buses travelling from city i to city i + 1.

Output

For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y is the maximum number of cities you can go sightseeing in such that you can still arrive at city N by time Tf at the latest. If it is impossible to arrive at city N by time Tf, output Case #x: IMPOSSIBLE.

Limits

1 ≤ T ≤ 100.
Small dataset

2 ≤ N ≤ 16.
1 ≤ Si ≤ 5000.
1 ≤ Fi ≤ 5000.
1 ≤ Di ≤ 5000.
1 ≤ Ts ≤ 5000.
1 ≤ Tf ≤ 5000.
Large dataset

2 ≤ N ≤ 2000.
1 ≤ Si ≤ 109.
1 ≤ Fi ≤ 109.
1 ≤ Di ≤ 109.
1 ≤ Ts ≤ 109.
1 ≤ Tf ≤ 109.
Sample


Input 
     
Output 
 
4
4 3 12
3 2 1
6 2 2
1 3 2
3 2 30
1 2 27
3 2 1
4 1 11
2 1 2
4 1 5
8 2 2
5 10 5000
14 27 31
27 11 44
30 8 20
2000 4000 3

Case #1: 2
Case #2: 0
Case #3: IMPOSSIBLE
Case #4: 4


In the first test case, you can go sightseeing in city 1, catching the bus leaving at time 3 and arriving at time 4. You can go sightseeing in city 2, leaving on the bus at time 8. When you arrive in city 3 at time 10 you immediately board the next bus and arrive in city 4 just in time at time 12.
View Code

题意:1 - N座城市,相邻两座之间有巴士(si, fi, di), 表示从si时刻开始每隔 fi 就有一辆巴士开向下一个城市,途中需要 di 的时间。

已知游客从0时刻在1城市出发开始旅游,每座城市可选择停留ts的时间游览,求在tf时间内到达N城的前提下,游客最多能游览的城市数(N城不算入游览的城市,即到达N城就结束)。

题解:small : n <= 16, 每座城市选择是否停留, 暴力dfs即可(O(2 ^ 16)).

large: dp[i][j] 表示经过i城市并总共浏览了j座城市后的最短时间。则:dp[i][j]  = min(dp[i - 1][j] + 等车时间 + d[i],  (dp[i - 1][j - 1] + ts) + 等车时间 + d[i])。

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int t, n;
ll ts, tf;
ll s[2005], f[2005], d[2005];
const ll INF=(1LL<<60)-1;
ll dp[2005][2005];
ll calc(ll cur, ll s, ll f) {
    if (cur <= s) return s;
    else return cur + (f - (cur - s) % f) % f;
}
void solve() {
    cin >> n >> ts >> tf;
    for (int i = 1; i < n; i++) {
        cin >> s[i] >> f[i] >> d[i];
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            dp[i][j] = INF;
        }
    }
    dp[0][0] = 0;
    ll t1, t2;
    for (int i = 1; i < n; i++) {
        dp[i][0] = calc(dp[i-1][0], s[i], f[i]) + d[i];
        for (int j = 1; j < i; j++) {
            dp[i][j] = min(calc(dp[i-1][j], s[i], f[i]), calc(dp[i-1][j - 1] + ts, s[i], f[i])) + d[i];
        }
        dp[i][i] = calc(dp[i-1][i-1] + ts, s[i], f[i]) + d[i];
    }
    int ans = -1;
    for (int i = 0; i < n; i++) {
        if (dp[n - 1][i] <= tf) {
            ans = i;
        }
    }
    if (ans < 0) printf("IMPOSSIBLE\n");
    else printf("%d\n", ans);
}
int main() {
    freopen("A-large.in", "r", stdin);
    freopen("A-large.out", "w", stdout);
    scanf("%d",&t);
    for (int tt = 1; tt <= t; tt++) {
        printf("Case #%d: ", tt);
        solve();
    }
}
View Code

C Trash Throwing

Problem

Bob is an outstanding Googler. He loves efficiency, so he does everything well and quickly. Today, Bob has discovered that the trash can near his desk has disappeared! Sadly, this means that he has to use another nearby trash can instead. Since getting out of his seat to use the trash can would lower his productivity, Bob has decided to throw his trash into that trash can!

But there are many obstacles in the Google office. For example, it is rude if the thrown trash hits somebody, or the wall, or anything else. Bob hopes to throw the trash without touching any existing obstacles.

To simplify this problem, we will only consider the vertical plane that includes Bob and the trash can. Bob is at point (0, 0); the trash can is at point (P, 0). Moreover, there are N obstacles in the office; each of them is a single point, and the i-th one has coordinates (Xi, Yi). The ceiling of the office is a line with the expression y=H in the plane. Since Bob is in one of the new high-tech floating offices, we do not consider the office floor in this problem; you do not need to worry about collisions with it. Bob will throw a piece of trash that is a circle with radius R. The center of the piece of trash starts off at (0, 0). When the piece of trash is thrown, the center of the piece of trash must follow the path of a parabola with the expression f(x)=ax(x-P), where 0 ≤ x ≤ P, and a can be any real number less than or equal to 0. The piece of trash is only considered thrown away when its center reaches the trash can's point, and it is not enough for some part of the piece of trash to just touch that point.

Bob is wondering: what is the largest piece of trash he can throw without hitting the ceiling or any obstacles? That is, we must find the maximum value of R for which there is at least one value a that satisfies the following: for any 0 ≤ x ≤ P, the Euclidean distance between (x, f(x)) and (x, H) is greater than R, and for each i, the Euclidean distance between the point (x, f(x)) and (Xi, Yi) is greater than or equal to R.

Input

The input starts with one line containing one integer T, the number of test cases. T test cases follow. The first line of each test case contains three integers N, P, and H: the number of obstacles, the x-coordinate of the trash can, and the height of the ceiling. Then, there are N more lines; the i-th of those lines represents the i-th obstacle, and has two integers Xi and Yi, representing that obstacle's coordinates.

Output

For each test case, output one line Case #x: y, where x is the test case number (starting from 1) and y is a double representing the maximum radius R. Your answer will be considered correct if it is within an absolute or relative error of 10-4 of the correct answer. See the FAQ for an explanation of what that means, and what formats of real numbers we accept.

Limits

1 ≤ T ≤ 50.
2 ≤ P ≤ 1000.
2 ≤ H ≤ 1000.
0 < Xi < P.
0 < Yi < H.
Small dataset

N = 1.
Large dataset

1 ≤ N ≤ 10.
Sample


Input 
     
Output 
 
4
1 10 10
5 3
1 10 10
5 4
1 100 10
50 3
2 10 10
4 2
6 7

Case #1: 3.23874149472
Case #2: 4.00000000000
Case #3: 3.50000000000
Case #4: 2.23145912401

Note that the last sample case would not appear in the Small dataset.

The following picture illustrates Sample Case #1. Bob is at (0, 0), and the trash can is at (10, 0). There is a obstacle at point (5, 3), marked with a star. If Bob throws trash over the top of the obstacle, the maximal R is 3.2387, which requires an a of about -0.2705. If Bob throws trash under the obstacle, the maximal R is 3, which requires an a of 0. So the maximum R for this case is about 3.2387.


Sample Case #2 is like Sample Case #1, but the obstacle is one unit higher. Now, if Bob throws the trash under the obstacle, the maximal R is 4 (for a = 0). If he throws the trash over the obstacle, he can only use trash with a radius up to about 2.8306 (with a = -0.4). So the maximum R for this case is 4.
View Code

题意:平面上一堆点(x, y) (0<x < P,   0 < y < H)。求所有点以及直线y = H 到曲线 f(x)=ax(x-P) 的最小距离的最大值。a   <= 0.

题解:

small 1: 当曲线从点的下面经过时,显然最优解为 a = 0, Lmin = y。 当曲线从点的上面经过时, 对最小距离二分([y, H]), 判断是否存在对应的a。

 

google kickstart 2017 round E

A . Copy & Paste

Problem

You want to create a certain target string S, which consists only of lowercase English letters. You start with an empty string, and you are allowed to perform the following operations:

Add any single lowercase letter to the end of your string.
Copy any substring of your string (that is, all of the characters between some start point in your string and some end point in your string) to the clipboard. Doing this overwrites whatever was in the clipboard before. The clipboard starts off empty.
Add the entire contents of the clipboard to the end of your string. (The contents of the clipboard do not change.)
What is the smallest number of operations needed to create your target string? Note that you must create exactly the target string, with no additional letters.

Input

The first line of the input gives the number of test cases, T. T lines follow. Each line contains the target string S.

Output

For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y is the minimum number of operations (as described in the problem statement) needed to create the target string.

Limits

S consists only of lowercase English letters in the range a through z.
Small dataset

1 ≤ T ≤ 100.
1 ≤ length of S ≤ 6.
Large dataset

1 ≤ T ≤ 100.
1 ≤ length of S ≤ 100.

Sample Input and Output 
3
abcabab
aaaaaaaaaaa
vnsdmvnsnsdmkvdmkvnsdmk

Case #1: 6
Case #2: 7
Case #3: 15

The optimal solution for Sample Case #1 is:

Type a.
Type b.
Type c.
Copy ab to the clipboard.
Paste ab at the end of the string.
Paste ab at the end of the string.

The optimal solution for Sample Case #2 is:
Type a.
Type a.
Type a.
Copy aaa to the clipboard.
Paste aaa at the end of the string.
Copy aaaaa to the clipboard.
Paste aaaaa at the end of the string.
View Code

题意 给定字符串,每次可以从三种操作中选择一种进行:

1 添加一个字符

2 将当前字符串的某个子串复制到粘贴板中,粘贴板之前的内容将会被清空

3 将粘贴板的内容粘贴到字符串后面

求从空字符串开始构建该字符串所需的最小操作次数。

solution1

dfs+memorization

#include <bits/stdc++.h>
using namespace std;
#define mp make_pair
string s;
map<pair<int, string>, int> p;
bool same(int index, int len, string str) {
    if(len!=str.size()) return false;
    int cur = 0;
    for (int i = 0; i < len; i++) {
        if (s[i+index]!=str[cur++]) return false;
    }
    return true;
}
bool gao(int index1, int index2, int len) {
    for (int i = 0; i <= len; i++) {
        if (s[index1+i]!=s[index2+i]) return false;
    }
    return true;
}
int solve(int cur, string clip) {
    if (p[mp(cur, clip)]) return p[mp(cur, clip)];
    if (cur >= s.size()) return 0;
    int ret = solve(cur+1, clip) + 1;
    string sub="";
    for (int len = 0; cur + len < s.size(); len++) {
        sub += s[cur+len];
        if (same(cur, len+1, clip)) {
            ret = min(ret, 1+solve(cur+len+1, clip));
        }
        for (int j = 0; j +len < cur; j++) {
            if (gao(cur, j, len)) {
                ret = min(ret, 2 + solve(cur+len+1, s.substr(cur, len+1)));
                break;
            }
        }
    }
    p[mp(cur, clip)] = ret;
    return ret;
}
int main() {
    freopen("A-small-practice.in", "r", stdin);
    freopen("A-small-practice.out", "w", stdout);
    int t;
    cin >> t;
    for (int i = 1; i <= t; i++) {
        cin >> s;
        p.clear();
        printf("Case #%d: %d\n", i, solve(0, ""));
    }
    return 0;
}
View Code

solution2 dp

dp[i][j][k]表示形成i长度的字符串,粘贴板内容为j-k子串的最小操作次数。则dp[i][j][k] 可以:

1 将任一子串复制到clip中 -> dp[i][j][k] = min(dp[i][_][_]) + 1

2 直接填下一个字符  -> dp[i+1][j][k] = dp[i][j][k] + 1

3 粘贴j-k子串的字符到字符串中 -> dp[ i+1+k-j ][j][k] = dp[i][j][k] + 1 (j-k子串与 i+1 - i+1+k-j 内容相同 O(N)复杂度判断, 可提前hash化O(1)判断)

dp[i][0][0] 表示粘贴板板内容为空。

初始状态 : dp[0][0][0] = 0, 结果 ans = min(dp[n][_][_])

#include <bits/stdc++.h>
using namespace std;
int dp[101][100][101];
const int inf = ~0U >> 1;
bool check(string s, int i, int j, int k) {
    for (int l = 0; l <= k-j; l++) {
        if (s[i+l] != s[j+l-1]) return false;
    }
    return true;
}
int solve() {
    string s;
    cin >> s;
    for (int i = 0; i < 101; i++) {
        for (int j = 0; j < 101; j++) {
            for (int k = 0; k < 101; k++) {
                dp[i][j][k] = inf;
            }
        }
    }

    int n = s.size();
    dp[1][0][0] = 1;
    for (int i = 1; i < n; i++) {
        int temp = inf;
        for (int j = 0; j <= i; j++) {
            for (int k = j; k <= i; k++) {
                temp = min(temp, dp[i][j][k]);
            }
        }
        for (int j = 1; j <= i; j++) {
            for (int k = j; k <= i; k++) {
                dp[i][j][k] = min(temp+1, dp[i][j][k]);
            }
        }
        dp[i+1][0][0]  = i+1;
        for (int j = 1; j <= i; j++) {
            for (int k = j; k <= i; k++) {
                if (dp[i][j][k] == inf) continue;
                dp[i+1][j][k] = min(dp[i+1][j][k], dp[i][j][k]+1);
                if (i+k-j+1 <= n && check(s, i, j, k)) {
                    dp[i+k-j+1][j][k] = min(dp[i+k-j+1][j][k], dp[i][j][k]+1);
                    dp[i+k-j+1][i+1][i+k-j+1] = min(dp[i+k-j+1][i+1][i+k-j+1], dp[i][j][k]+1);
                }
            }
        }
    }
    int ans = n;
    for (int j = 0; j <=n; j++) {
        for (int k = j; k < n; k++) {
            ans = min(ans, dp[n][j][k]);
        }
    }
    return ans;
}

int main(){
    int t;
    cin >> t;
    for (int tt = 1; tt <= t; tt++) {
        printf("Case #%d: %d\n", tt, solve());
    }
    return 0;
}
View Code

O(N4)复杂度 提前将字符串hash化, 可降至O(N3)

B Trapezoid Counting

Problem

In this problem, we will consider a trapezoid to be a convex quadrilateral with exactly one pair of parallel sides. If the lengths of the two non-parallel sides are equal, we say the trapezoid is isosceles.

You have some wooden sticks of various lengths, and you need to pick exactly four of them to form the four sides of an isosceles trapezoid. How many different sets of four sticks will allow this? Even if two sticks have the same length, they are considered to be different sticks. Sticks could not be bended and broke into parts.

Input

The first line of the input gives the number of test cases, T. T test cases follow; each consists of two lines. The first line consists of one integer N, the number of sticks. The second line consists of N integers; the i-th of these, Li, represents the length of the i-th stick.

Output

For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1), and y is the number of different sets of four sticks that can form an isosceles trapezoid, as described above.

Limits

1 ≤ T ≤ 100.
1 ≤ Li ≤ 109.
Small dataset

1 ≤ N ≤ 50.
Large dataset

1 ≤ N ≤ 5000.

Sample
 
5
5
2 3 3 4 3
4
1 5 3 1
4
2 2 3 3
4
999999998 999999999 999999999 1000000000
9
3 4 1 4 2 5 3 1 3

Case #1: 5
Case #2: 0
Case #3: 0
Case #4: 1
Case #5: 73

In Sample Case #1, there are five ways to choose four out of the five given sticks, and any one of those five sets of four sticks can be used to form an isosceles trapezoid. 
In Sample Case #2, note that the set {1, 1, 3, 5} cannot form an isosceles trapezoid, even though two of its sticks are of equal length.
In Sample Case #3, note that the set {2, 2, 3, 3} can form a rectangle, but in this problem, a rectangle is not considered to be an isosceles trapezoid.
View Code

题意:给定一个数组表示线段长度,从中取出四条线段,求有多少种取法能让这四条线段构成等腰梯形(矩形不算)。

small: 暴力枚举即可, O(n4)。设腰的长度为c, 两条平行边为a,b(a > b)。 则有 a  = b + 2 * c * cos(θ)  0 < θ < 90。 则有a > b, a < b + 2 * c。

large:

用一个map 存储每个数出现的次数。 然后枚举腰长,对于特定的腰,再用双指针枚举b,a的总取法即可, 注意b,a和c相等时即可。复杂度:O(n2)

#include<bits/stdc++.h>
using namespace std;
#define pit map<int,int>::iterator
using ll = long long;
int a[5010];
ll calc(pit it, pit it2, ll cnt) {
    ll ret = 0;
    ll ca = it->second, cb = it2->second;
    if (it == it2) {
        ret = 1LL*cnt*ca*(ca-1)*(ca-2)/6;
    } else if (it-> first < it2->first){
        ret = 1LL*ca*(ca-1)/2*cb*cnt;
    } else {
        ret = 1LL*cb*(cnt-ca)*(ca-1)*ca/2 + 1LL*cb*ca*(ca-1)*(ca-2)/6;
    }
    return ret;
}
ll solve() {
    int n;
    map<int,int> p;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        p[a[i]]++;
    }
    ll ans = 0;
    for (auto it = p.begin(); it != p.end(); ++it) {
        if (it->second < 2) continue;
        ll cnt = 0;
        auto it3 = ++p.begin();
        for (auto it2 = p.begin(); it2 != p.end();) {
            while (it3!= p.end() && it3->first - it2->first < 2 * it->first) {
                cnt += it3->second;
                ++it3;
            }
            ans += calc(it, it2, cnt);
            cnt = max(0LL, cnt - (++it2)->second);
            if (it2==it3) ++it3;
        }
    }
    return ans;
}
int main() {
    ios::sync_with_stdio(false);
    freopen("B-large-practice.in", "r", stdin);
    freopen("B-large-practice.out", "w", stdout);
    int t;
    cin >> t;
    for (int tt = 1; tt <= t; tt++) {
        printf("Case #%d: %lld\n", tt, solve());
    }
}
View Code

 C. Blackhole

Problem

Alice is trying to prevent dangerous black holes from threatening Earth. Right now, there are three black holes that are different points in 3-D space. Alice will create exactly three containment spheres, and all three must have the same radius. Spheres do not interfere with each other, so they may overlap.

Alice must place these spheres so that each black hole is covered by at least one sphere. Moreover, to ensure stability, the total set of points covered by at least one sphere must form a single connected area.

Alice wants to solve this critical problem as inexpensively as possible. What is the minimum radius that she can use?

Input

The input starts with one line with one integer T: the number of test cases. T test cases follow. Each test case consists of three lines. The i-th of those lines consists of three integers Xi, Yi, and Zi, representing the 3-D coordinates of the i-th black hole.

Output

For each test case, output one line Case #x: y, where x is the test case number (starting from 1) and y is a rational representing the minimum radius that Alice can use to solve the problem. y will be considered correct if it is within an absolute or relative error of 10-6 of the correct answer. See the FAQ for an explanation of what that means, and what formats of real numbers we accept.

Limits

1 ≤ T ≤ 100.
-1000 ≤ Xi ≤ 1000, for all i.
For all j ≠ k, (Xj, Yj, Zj) ≠ (Xk, Yk, Zk). (No two of the points have the same coordinates.)
Small dataset

Yi = 0, for all i.
Zi = 0, for all i.
Large dataset

-1000 ≤ Yi ≤ 1000, for all i.
-1000 ≤ Zi ≤ 1000, for all i.
Sample


Input 
     
Output 
 
4
0 0 0
1 0 0
-1 0 0
4 0 0
5 0 0
-2 0 0
0 0 0
1 1 1
-1 -1 -1
-4 2 -2
5 1 -4
0 4 -9

Case #1: 0.3333333333
Case #2: 1.1666666667
Case #3: 0.5773502692
Case #4: 2.1373179212

Note that the last two sample cases would not appear in the Small dataset.
In Sample Case #1, the smallest radius we can use is 1/3. Our three spheres should be centered at (-2/3, 0, 0), (0, 0, 0), and (2/3, 0, 0).
View Code

题意;空间中有三个点,求最小的r, 使得三个半径为r的球体能包住这三个点,而且这三个球体必须连通。

好难啊,不会。。。 只知道应该用二分。

posted @ 2017-05-08 16:52  hxidkd  阅读(475)  评论(0编辑  收藏  举报