• Petrozavodsk WinterTraining 2015


    PetrozavodskWinterTraining2015

    A - Three Servers

    题目描述:有(n)个数,将这(n)个数分成(3)堆,使得(3)堆中和的最大值减最小值最小,求方案。

    solution
    (f[i][j])表示第二堆减第一堆等于(i),第三堆减第二堆等于(j)的方案。由于数字比较小,所以可以定(-100 leq i, j leq 100),然后将读入数据随机排序,做(10)次就可以过了。

    时间复杂度:(O(能过))

    F - Empty Vessels

    题目描述:有(n)个水杯,每个水杯的容量为(a_i),现在有(3)种操作:

    1. 将某个水杯装满水
    2. 将某个水杯里的水倒掉
    3. 将某个水杯里的水倒到另一个水杯里,直到一个水杯满或一个水杯空
      给定一个值(m),问是否通过若干次操作之后某个水杯里的水体积为(m),求出方案。

    solution
    显然,(m)一定要是(a_i)的最大公约数的倍数,并且(m)要小于(a_i)的最大值。
    然后将最大的水杯看做剩余系,所有水杯往最大的水杯倒水,相当于水量模最大水杯容量,然后像完全背包那样做即可。

    时间复杂度:(O(最大容量*n))

    G - Maximum Product

    solution

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int maxn=30;
    
    LL A, B;
    int a[maxn], b[maxn], now[maxn];
    
    void calc(LL num, int *a)
    {
    	if (num==0) a[a[0]=1]=0;
    	a[0]=0;
    	while (num)
    	{
    		a[++a[0]]=num%10;
    		num/=10;
    	}
    }
    bool check()
    {
    	if (now[0]!=a[0]) return now[0]>a[0];
    	for (int i=now[0]; i; --i)
    		if (now[i]!=a[i]) return now[i]>a[i];
    	return true;
    }
    void solve()
    {
    	scanf("%lld%lld", &A, &B);
    	calc(A, a);
    	calc(B, b);
    
    	LL answer=1, ans=B;
    	for (int i=1; i<=b[0]; ++i) answer*=b[i];
    
    	for (int i=b[0]; i; --i)
    	{
    		for (int j=b[0]; j>i; --j) now[j]=b[j];
    		now[i]=b[i]-1;
    		for (int j=i-1; j; --j) now[j]=9;
    		for (int j=i; j<b[0]; ++j)
    			if (now[j]<0)
    			{
    				now[j]+=10;
    				now[j+1]--;
    			}
    			else break;
    		now[0]=b[0];
    		if (now[0]>1 && now[now[0]]==0) --now[0];
    		if (check())
    		{
    			LL s=1;
    			for (int j=1; j<=now[0]; ++j) s*=now[j];
    			if (s>answer)
    			{
    				answer=s;
    				ans=0;
    				for (int j=now[0]; j; --j) ans=ans*10+now[j];
    			}
    		}
    	}
    	printf("%lld
    ", ans);
    }
    int main()
    {
    	solve();
    	return 0;
    }
    

    H - Biathlon 2.0

    题目描述:分别给定(n, m)个向量,对于(n)里面的每个向量,在(m)中找一个向量,使得两个向量的点乘最小。

    solution
    根据点乘的意义,相当于是一个向量在另一个向量的投影,因此可以想到只有(m)个向量形成的下凸壳,在下凸壳上的点才是答案,将(n)个向量极角排序,然后每个向量对应的答案在下凸壳上是单调的。

    时间复杂度:(O(nlogn))

    I - Archaeological Research

    题目描述:有一个未知序列(a_i),给出一些数据,第(i)行第(j)个数据表示某个数在序列的第(i+1)个数后面(包括(i+1))第一次出现的位置是(j),找出(a_i)的可行解中字典序最小的一个。

    solution
    题目还可以用另一种方式表达:第(i)行第(j)个数据表示某个数在序列的第(i+1)位到第(j-1)位没出现过,进而可以求出(a_i)([l_i, i-1])没出现过,然后只要贪心地从左到右放数,每次取([1, l_i-1])中最小的数,如果(l_i=1),那么新开一个数字给(a_i)

    时间复杂度:(O(nlogn))

    J - Sockets

    题目描述:有一个电源(只有一个插座),(n)个排插,分别有(a_i)个插座,每个排插可以直接接电源或者插到别的排插上,有(m)部手机需要同时充电,每部手机规定到电源之间最多能有(b_i)个排插,问最多能有多少部手机同时充电。

    solution
    将排插按(a_i)从大到小排序,手机按(b_i)从小到大排序,二分答案,先满足(b_i)较小的,其它位置插排插。

    时间复杂度:(O(nlogn))

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int maxn=int(2e5)+100;
    
    int n, m;
    int a[maxn], b[maxn];
    
    
    void read()
    {
    	scanf("%d%d", &n, &m);
    	for (int i=1; i<=n; ++i) scanf("%d", &a[i]);
    	for (int i=1; i<=m; ++i) scanf("%d", &b[i]);
    }
    bool check(int num)
    {
    	LL rest=1;
    	for (int i=1, level=0; i<=n && num; ++level)
    	{
    		int k=num;
    		while (k && b[k]==level) --k;
    		if (num-k>rest) return false;
    		LL tmp=(rest-=(num-k));
    		num=k;
    		while (i<=n && (tmp--)) rest+=a[i++]-1;
    	}
    	return rest>=num;
    }
    void solve()
    {
    	sort(a+1, a+1+n, greater<int>());
    	sort(b+1, b+1+m, greater<int>());
    
    	int L=0, R=m+1;
    	while (L+1<R)
    	{
    		int mid=(L+R)>>1;
    		if (check(mid)) L=mid;
    		else R=mid;
    	}
    	printf("%d
    ", L);
    }
    int main()
    {
    	read();
    	solve();
    	return 0;
    }
    

    K - Toll Roads

    题目描述:给定一棵树,边权为(1),现在可以选择一条长度不超过(m)的链,将链上的边权全改为(0),使得树的直径最小,求方案。

    solution
    思路挺好想的,就是枚举一端作为树根,然后类似树形(dp)算出当另一端某个点时,树的直径是多少。

    时间复杂度:(O(n^2))

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn=5010;
    
    int n, m, root;
    vector<int> out[maxn];
    int idx[maxn];
    pair<int, int> le[maxn], ri[maxn];
    int radle[maxn], radri[maxn];
    int fa[maxn], f[maxn], g[maxn], h[maxn];
    int rad[maxn], deep[maxn];
    pair<int, int> ans, solu;
    
    void read()
    {
    	scanf("%d%d", &n, &m);
    	for (int i=0; i<n; ++i) out[i].clear();
    	for (int i=1; i<n; ++i)
    	{
    		int u, v;
    		scanf("%d%d", &u, &v);
    		out[u].push_back(v);
    		out[v].push_back(u);
    	}
    }
    void dfs1(int cur, int _fa)
    {
    	rad[cur]=0;
    	f[cur]=0;
    	fa[cur]=_fa;
    	if (_fa==-1) deep[cur]=0;
    	else deep[cur]=deep[_fa]+1;
    	for (auto &to:out[cur])
    	if (to!=_fa)
    	{
    		dfs1(to, cur);
    		rad[cur]=max(rad[cur], max(rad[to], f[cur]+f[to]+1));
    		f[cur]=max(f[cur], f[to]+1);
    	}
    }
    void dfs2(int cur, int past, int chain)
    {
    	if (deep[cur]>m) return;
    	int s=max(past, max(rad[cur], chain+f[cur]));
    	if (make_pair(s, deep[cur])<ans)
    	{
    		ans=make_pair(s, deep[cur]);
    		solu=make_pair(root, cur);
    	}
    	int cnt=0;
    	for (auto &to:out[cur])
    		if (to!=fa[cur]) idx[++cnt]=to;
    	le[1]=make_pair(0, 0);
    	radle[1]=0;
    	for (int i=2; i<=cnt; ++i)
    	{
    		le[i]=le[i-1];
    		radle[i]=max(radle[i-1], rad[idx[i-1]]);
    		if (f[idx[i-1]]+1>le[i].first)
    		{
    			le[i].second=le[i].first;
    			le[i].first=f[idx[i-1]]+1;
    		}
    		else le[i].second=max(le[i].second, f[idx[i-1]]+1);
    	}
    	ri[cnt]=make_pair(0, 0);
    	radri[cnt]=0;
    	for (int i=cnt-1; i>0; --i)
    	{
    		ri[i]=ri[i+1];
    		radri[i]=max(radri[i+1], rad[idx[i+1]]);
    		if (f[idx[i+1]]+1>ri[i].first)
    		{
    			ri[i].second=ri[i].first;
    			ri[i].first=f[idx[i+1]]+1;
    		}
    		else ri[i].second=max(ri[i].second, f[idx[i+1]]+1);
    	}
    	for (int i=1; i<=cnt; ++i)
    	{
    		g[idx[i]]=max(le[i].first, ri[i].first);
    		h[idx[i]]=max(le[i].first+ri[i].first, max(le[i].first+le[i].second, ri[i].first+ri[i].second));
    		h[idx[i]]=max(h[idx[i]], max(radle[i], radri[i]));
    	}
    	for (auto &to:out[cur])
    		if (to!=fa[cur]) dfs2(to, max(past, max(h[to], chain+g[to])), max(chain, g[to]));
    }
    void solve()
    {
    	ans=make_pair(n*2, 0);
    	for (int i=0; i<n; ++i)
    	{
    		root=i;
    		dfs1(i, -1);
    		dfs2(i, 0, 0);
    	}
    	printf("%d
    %d
    ", ans.first, ans.second);
    	if (ans.second) printf("%d %d
    ", solu.first, solu.second);
    }
    int main()
    {
    	read();
    	solve();
    	return 0;
    }
    
  • 相关阅读:
    Android:JNI与NDK(一)
    okio:定义简短高效
    hashCode()方法以及集合中Set的一些总结
    Gradle入门到实战(二) — ImageOptimization安卓图片转换压缩插件
    Gradle入门到实战(一) — 全面了解Gradle
    数据结构与算法(十二):八大经典排序算法再回顾
    数据结构与算法(十一):图的基础以及遍历代码实现
    数据结构与算法(十):红黑树与TreeMap详细解析
    数据结构与算法(九):AVL树详细讲解
    Android版数据结构与算法(八):二叉排序树
  • 原文地址:https://www.cnblogs.com/GerynOhenz/p/9892634.html
Copyright © 2020-2023  润新知