Codeforces Round #661 (Div. 3) D E1

目录

D. Binary String To Subsequences

E1. Weights Division (easy version)


D. Binary String To Subsequences

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

You are given a binary string ss consisting of nn zeros and ones.

Your task is to divide the given string into the minimum number of subsequences in such a way that each character of the string belongs to exactly one subsequence and each subsequence looks like "010101 ..." or "101010 ..." (i.e. the subsequence should not contain two adjacent zeros or ones).

Recall that a subsequence is a sequence that can be derived from the given sequence by deleting zero or more elements without changing the order of the remaining elements. For example, subsequences of "1011101" are "0", "1", "11111", "0111", "101", "1001", but not "000", "101010" and "11100".

You have to answer tt independent test cases.

Input

The first line of the input contains one integer tt (1≤t≤2⋅1041≤t≤2⋅104) — the number of test cases. Then tt test cases follow.

The first line of the test case contains one integer nn (1≤n≤2⋅1051≤n≤2⋅105) — the length of ss. The second line of the test case contains nn characters '0' and '1' — the string ss.

It is guaranteed that the sum of nn does not exceed 2⋅1052⋅105 (∑n≤2⋅105∑n≤2⋅105).

Output

For each test case, print the answer: in the first line print one integer kk (1≤k≤n1≤k≤n) — the minimum number of subsequences you can divide the string ss to. In the second line print nn integers a1,a2,…,ana1,a2,…,an (1≤ai≤k1≤ai≤k), where aiai is the number of subsequence the ii-th character of ss belongs to.

If there are several answers, you can print any.

Example

input

Copy

4
4
0011
6
111111
5
10101
8
01010000

output

Copy

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

思路:双队列模拟。末尾为1的子序列号保存在queue1,末尾为0的子序列号保存在queue0.遇到1从queue0中取,遇到0从queue1中取。

#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<cstring>
#include<queue>
#define ll long long
 
using namespace std;
 
const int N = 2e5+10;
 
int ans[N];
char tem[N];


int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		queue<int> q1;
		queue<int> q0;
		int cnt = 0;
		int n;
		cin>>n;
		string s;
		cin>>s;
		for(int i=0; i<n; i++)
		{
			if(s[i] == '0') 
			{
				if(q1.size())
				{
					ans[i] = q1.front();
					q1.pop();
					q0.push(ans[i]);
				}
				else
				{
					cnt++;
					ans[i] = cnt;
					q0.push(cnt);
				}
			}
			
			if(s[i] == '1')
			{
				if(q0.size())
				{
					ans[i] = q0.front();
					q0.pop();
					q1.push(ans[i]);
				}
				else
				{
					cnt++;
					ans[i] = cnt;
					q1.push(cnt);
				}
			}			
		}
		cout<<cnt<<endl;
		for(int i=0; i<n; i++)
			cout<<ans[i]<<' ';
		puts("");
	}	
	return 0;
}

E1. Weights Division (easy version)

time limit per test

3 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Easy and hard versions are actually different problems, so we advise you to read both statements carefully.

You are given a weighted rooted tree, vertex 11 is the root of this tree.

A tree is a connected graph without cycles. A rooted tree has a special vertex called the root. A parent of a vertex vv is the last different from vv vertex on the path from the root to the vertex vv. Children of vertex vv are all vertices for which vv is the parent. A vertex is a leaf if it has no children. The weighted tree is such a tree that each edge of this tree has some weight.

The weight of the path is the sum of edges weights on this path. The weight of the path from the vertex to itself is 00.

You can make a sequence of zero or more moves. On each move, you select an edge and divide its weight by 22 rounding down. More formally, during one move, you choose some edge ii and divide its weight by 22 rounding down (wi:=⌊wi2⌋wi:=⌊wi2⌋).

Your task is to find the minimum number of moves required to make the sum of weights of paths from the root to each leaf at most SS. In other words, if w(i,j)w(i,j) is the weight of the path from the vertex ii to the vertex jj, then you have to make ∑v∈leavesw(root,v)≤S∑v∈leavesw(root,v)≤S, where leavesleaves is the list of all leaves.

You have to answer tt independent test cases.

Input

The first line of the input contains one integer tt (1≤t≤2⋅1041≤t≤2⋅104) — the number of test cases. Then tt test cases follow.

The first line of the test case contains two integers nn and SS (2≤n≤105;1≤S≤10162≤n≤105;1≤S≤1016) — the number of vertices in the tree and the maximum possible sum of weights you have to obtain. The next n−1n−1 lines describe edges of the tree. The edge ii is described as three integers vivi, uiui and wiwi (1≤vi,ui≤n;1≤wi≤1061≤vi,ui≤n;1≤wi≤106), where vivi and uiui are vertices the edge ii connects and wiwi is the weight of this edge.

It is guaranteed that the sum of nn does not exceed 105105 (∑n≤105∑n≤105).

Output

For each test case, print the answer: the minimum number of moves required to make the sum of weights of paths from the root to each leaf at most SS.

Example

input

Copy

3
3 20
2 1 8
3 1 7
5 50
1 3 100
1 5 10
2 3 123
5 4 55
2 100
1 2 409

output

Copy

0
8
3

题意:一棵树,可以将任何边的权值减半,求需要操作多少次,使根节点到所有叶子节点的距离和sum小于等于s.

思路:首先dfs求出每个边被使用的次数,再求出该边权值减半后的缩小量,很明显,我们要先对缩小量大的树枝进行减半,可以利用set的自动排序,不停的减去最大缩小量,直到sum<=s.

#include<iostream>
#include<set>
#include<algorithm>
#include<cstring>
#include<vector>
#define ll long long 

using namespace std;

const int N = 2e5 + 10;

int n;
ll s;
typedef pair<ll,int> PII;
vector<PII> v[N];
ll cnt[N];
ll w[N];

void dfs(int u, int fa)
{
	if(v[u].size() ==  1)
	{
		cnt[fa] = 1;
	}
	
	for(auto a : v[u])
	{
		int v = a.first;
		int e = a.second;
		if(e == fa) continue;
		dfs(v, e);
		if(fa != -1) cnt[fa] += cnt[e];
	}
}

ll get_sum(int i)
{
	return cnt[i] * w[i] - w[i] / 2 * cnt[i];
}

int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		cin>>n>>s;
		for(int i=1; i<=n; i++) v[i].clear();
		memset(cnt, 0, sizeof cnt);		
		int a,b,c;
		for(int i=0; i<n-1; i++)
		{
			scanf("%d%d%d",&a,&b,&c);
			v[a].push_back({b,i});
			v[b].push_back({a,i});
			w[i] = c;
		}
		
		dfs(1,-1);
		ll sum = 0;
		set<PII> se;//自动从小到大排序 
		for(int i=0; i<n-1; i++)
		{
			se.insert({get_sum(i),i});
			sum += (ll)cnt[i] * w[i];
		}
		
		int step = 0;
		
		while(s < sum)
		{
			int id = se.rbegin() -> second;//rbegin()指向set最后一个元素,rend指向 set第一个元素前面的位置 
			ll a = se.rbegin() -> first;
			sum -= a;
			set<PII> :: iterator last = se.end();//end()指向最后一个元素的后一个元素 
			se.erase(--last);
			w[id] /= 2;
			se.insert({get_sum(id), id});
			step++;
		}
		cout<<step<<endl;
	}
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值