2018 Multi-University Training Contest 1

B .

Problem Description
Chiaki has n strings s1,s2,…,sn consisting of '(' and ')'. A string of this type is said to be balanced:

+ if it is the empty string
+ if A and B are balanced, AB is balanced,
+ if A is balanced, (A) is balanced.

Chiaki can reorder the strings and then concatenate them get a new string t. Let f(t) be the length of the longest balanced subsequence (not necessary continuous) of t. Chiaki would like to know the maximum value of f(t) for all possible t.
 

Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
The first line contains an integer n (1≤n≤105) -- the number of strings.
Each of the next n lines contains a string si (1≤|si|≤105) consisting of `(' and `)'.
It is guaranteed that the sum of all |si| does not exceeds 5×106.
 

Output
For each test case, output an integer denoting the answer.
 

Sample Input

2
1
)()(()(
2
)
)(

 

Sample Output

4
2

题意 : 给你 n 个括号序列,你可以任意对这 n 组括号排序,组成一个新的括号序列,求最多匹配的括号有多少个 ?

思路分析 : 括号匹配的过程就是一个栈模拟的过程,对最开始的序列进行操作的话只要有可以匹配的括号我们就去匹配,那么我们会得到一串 )))))((((((( 的括号,按照一定顺序去排这些括号就可以了,类似流水线调度法则 。

关于流水作业调度问题的以下 Johnson 算法:

(1) 令 AB = { i | ai < bi}, BA = { i | ai ≥ bi } ;
(2) 将 AB 中作业依 ai 的非减次序排列;将 BA 中作业依 b的非增次序排列;

(3) AB 中作业接 BA 中作业即构成满足 Johnson 法则的最优调度。

代码示例 :

 

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e5+5;

int n;
char s[maxn];
struct node
{
    int l, r, sum;
    node(int _l, int _r, int _sum):l(_l),r(_r),sum(_sum){}
};
bool cmp1(node a, node b){
	return a.r < b.r;
}
bool cmp2(node a, node b){
	return a.l > b.l;
}
vector<node>v1, v2;

int main () {
    int t;
    
    cin >> t;
    while(t--){
        v1.clear(), v2.clear();
		scanf("%d", &n);
        for(int i = 1; i <= n; i++){
            scanf("%s", s+1);
            int len = strlen(s+1);
            int l = 0, r = 0, sum = 0;
            for(int j = 1; j <= len; j++){
                if (s[j] == '(') l++;
                else {
                    if (l) sum++, l--;
                    else r++;
                }
            }    
            if (r < l) v1.push_back(node(l, r, sum));
            else v2.push_back(node(l, r, sum));
        }    
        sort(v1.begin(), v1.end(), cmp1);
        sort(v2.begin(), v2.end(), cmp2);
        v1.insert(v1.end(), v2.begin(), v2.end());
		int f = 0, ans = 0;
        for(int i = 0; i < v1.size(); i++){
			ans += v1[i].sum;
            if (f >= v1[i].r) {
                ans += v1[i].r;
                f -= v1[i].r;
                f += v1[i].l; 
            } 
            else {
                ans += f;
                f = v1[i].l;
            }
        }
        printf("%d\n", ans*2);
    }
    
    
    return 0;
}

 Distinct Values
Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4805    Accepted Submission(s): 1635


Problem Description
Chiaki has an array of n positive integers. You are told some facts about the array: for every two elements ai and aj in the subarray al..r (l≤i<j≤r), ai≠aj holds.
Chiaki would like to find a lexicographically minimal array which meets the facts.
 

Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains two integers n and m (1≤n,m≤105) -- the length of the array and the number of facts. Each of the next m lines contains two integers li and ri (1≤li≤ri≤n).

It is guaranteed that neither the sum of all n nor the sum of all m exceeds 106.
 

Output
For each test case, output n integers denoting the lexicographically minimal array. Integers should be separated by a single space, and no extra spaces are allowed at the end of lines.
 

Sample Input

3
2 1
1 2
4 2
1 2
3 4
5 2
1 3
2 4

 

Sample Output

1 2
1 2 1 2
1 2 3 1 1

 

题意 : 给你一个序列的长度,表示你将要去填充的序列的长度,有一个规则是这样的,就是会指定一些区间他们之间是不能有相同的元素的,但是同时也要求整个构造的序列的字典序最小

思路分析 : 贪心

    确保所维护的区间序列偏小的元素尽可能都在序列中即可,用 set 或优先队列都可以

代码示例 :

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;

int n, m;
int tail[maxn], ans[maxn];
set<int>s;

void solve() {
	int l = 1, r = 0;
	s.clear();
	for(int i = 1; i <= n; i++) s.insert(i);
	
	for(int i = 1; i <= n; i++){
		if (tail[i] <= r) continue;
		while(l < i){
			s.insert(ans[l++]);		
		}
		while(r < tail[i]){
			ans[++r] = *s.begin();
			s.erase(s.begin());
		}
	}
}

int main () {
	int t;
	int l, r;
	
	cin >> t;
	while(t--){
		cin >> n >> m;
		for(int i = 1; i <= n; i++) tail[i] = i;
		for(int i = 1; i <= m; i++){
			scanf("%d%d", &l, &r);		
			tail[l] = max(r, tail[l]);
		}
		solve();
		
		for(int i = 1; i <= n; i++) printf("%d%c", ans[i], i==n?'\n':' ');
	}
	return 0;
}

 Problem Description
Chiaki is interested in an infinite sequence a1,a2,a3,..., which is defined as follows:
an={1an?an?1+an?1?an?2n=1,2n≥3

Chiaki would like to know the sum of the first n terms of the sequence, i.e. ∑i=1nai. As this number may be very large, Chiaki is only interested in its remainder modulo (109+7).
 

Input
There are multiple test cases. The first line of input contains an integer T (1≤T≤105), indicating the number of test cases. For each test case:
The first line contains an integer n (1≤n≤1018).
 

Output
For each test case, output an integer denoting the answer.
 

Sample Input

10
1
2
3
4
5
6
7
8
9
10

 

Sample Output

1
2
4
6
9
13
17
21
26
32

题意 : 给你 一个an 的通项公式,让你去求前 n 项的和时多少

思路分析 : 首先要做的事情肯定是打一张表,去看一下an 有什么规律,然后我们会发现 an 是连续出现的,只不过数字出现的次数不相同而已,然后会惊奇的发现数字出现的次数取决于它的 lowbit 值

根据这些再去求答案就很容易了,我们去二分 an, 但这里要注意的一点就是要大致的给一个二分的范围否则会超时

代码示例 :

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxn = 1e5+5;
const ll mod = 1e9+7;

ll n, x;

bool check(ll x){
    ll res = 0;
    for(ll i = 1; i <= 61; i++){
        ll s = (1ll)<<(i-1);
        if (s > x) break;
        ll cha = (1ll)<<i;
        ll f = (x-s)/cha+1;
        res += f*i;
    }
    return (res+1) >= n;
}
ll fun(ll l, ll r) {
    ll num = 0;
    while(l <= r){
        ll mid = l+(r-l)/2;
        if (check(mid)) {num = mid; r = mid - 1;}
        else l = mid+1;
    }
    return num;
}

void solve() {
    ll sum = 1;
    ll sm = 0;
    for(ll i = 1; i <= 61; i++){
        ll s = (1ll)<<(i-1);
        if (s > x) break;
        ll cha = (1ll)<<i;
        ll f = (x-s)/cha+1;
        s %= mod, f %= mod; cha %= mod;
        ll num = s*f%mod + f*(f-1)%mod*500000004%mod*cha%mod;
        num %= mod;
        sum += num*i%mod; sum %= mod;
        sm += i*f;
    }
	x %= mod;
    sum = (sum-(sm-n+1)%mod*x%mod)%mod;
    printf("%lld\n", (sum+mod)%mod);
}

int main () {
    ll t;
    
    cin >> t;
    while(t--){
        scanf("%lld", &n);    
        ll l = max(n/2-30, 1ll), r = n/2+30;
        x = fun(l, r);
        solve();
    }
    return 0;
}

 

posted @ 2018-08-24 09:09  楼主好菜啊  阅读(157)  评论(0编辑  收藏  举报