2020 Multi-University Training Contest 2

1010 Lead of Wisdom(爆搜优化)

Problem Description
In an online game, “Lead of Wisdom” is a place where the lucky player can randomly get powerful items.
There are k types of items, a player can wear at most one item for each type. For the i-th item, it has four attributes ai,bi,ci and di. Assume the set of items that the player wearing is S, the damage rate of the player DMG can be calculated by the formula:

D M G = ( 100 + ∑ i ∈ S a i ) ∗ ( 100 + ∑ i ∈ S b i ) ∗ ( 100 + ∑ i ∈ S c i ) ∗ ( 100 + ∑ i ∈ S d i ) DMG=(100+\sum_{i∈S}a_i)*(100+∑_{i∈S}b_i)*(100+∑_{i∈S}c_i)*(100+∑_{i∈S}d_i) DMG=(100+iSai)(100+iSbi)(100+iSci)(100+iSdi)

Little Q has got n items from “Lead of Wisdom”, please write a program to help him select which items to wear such that the value of DMG is maximized.
Input
The first line of the input contains a single integer T (1≤T≤10), the number of test cases.
For each case, the first line of the input contains two integers n and k (1≤n,k≤50), denoting the number of items and the number of item types.
Each of the following n lines contains five integers ti,ai,bi,ci and di (1≤ti≤k, 0≤ai,bi,ci,di≤100), denoting an item of type ti whose attributes are

其实就是爆搜一波,但是就非得卡你 (T你),在dfs里处理 num[x]==0 的情况也不行,非得先在dfs外预处理一下。

#include    //本来就是一个爆搜签到  非得这样吗
#include
#include
using namespace std;
typedef long long LL;

struct Node{
    LL a,b,c,d;
};
int n,k;
LL ans;
LL n1,n2,n3,n4;
vector<Node> it[100];
vector<int> v;

void dfs(int x)
{
    if(x>=v.size()){
        ans = max(ans,n1*n2*n3*n4);
        return ;
    }
    int t = v[x];
    for(int i=0;i<it[t].size();i++){
        n1+=it[t][i].a,n2+=it[t][i].b,n3+=it[t][i].c,n4+=it[t][i].d;
           dfs(x+1);
        n1-=it[t][i].a,n2-=it[t][i].b,n3-=it[t][i].c,n4-=it[t][i].d;
    }
}

int main()
{
    int T; scanf("%d",&T);
    LL t,a,b,c,d;
    while(T--){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%lld%lld%lld%lld%lld",&t,&a,&b,&c,&d);
            it[t].push_back({a,b,c,d});
            v.push_back(t);
        }
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());
        ans=0,n1=100,n2=100,n3=100,n4=100;
        dfs(0);
        cout<<ans<<"\n";
        for(int i=0;i<=k;i++) it[i].clear();
        v.clear();
    }
    return 0;
}

1006 The Oculus (数学、思维)

Problem Description
Let’s define the Fibonacci sequence F1,F2,… as F1=1,F2=2,Fi=Fi−1+Fi−2 (i≥3).
It’s well known that every positive integer x has its unique Fibonacci representation (b1,b2,…,bn) such that:
· b1×F1+b2×F2+⋯+bn×Fn=x.
· bn=1, and for each i (1≤i · For each i (1≤i
For example, 4=(1,0,1), 5=(0,0,0,1), and 20=(0,1,0,1,0,1) because 20=F2+F4+F6=2+5+13.
There are two positive integers A and B written in Fibonacci representation, Skywalkert calculated the product of A and B and written the result C in Fibonacci representation. Assume the Fibonacci representation of C is (b1,b2,…,bn), Little Q then selected a bit k (1≤k It is so slow for Skywalkert to calculate the correct result again using Fast Fourier Transform and tedious reduction. Please help Skywalkert to find which bit k was modified.
Input
The first line of the input contains a single integer T (1≤T≤10000), the number of test cases.
For each case, the first line of the input contains the Fibonacci representation of A, the second line contains the Fibonacci representation of B, and the third line contains the Fibonacci representation of modified C.
Each line starts with an integer n, denoting the length of the Fibonacci representation, followed by n integers b1,b2,…,bn, denoting the value of each bit.
It is guaranteed that:
· 1≤|A|,|B|≤1000000.
· 2≤|C|≤|A|+|B|+1.
·∑|A|,∑|B|≤5000000.

这个题还是比较友好的,根据题意 A ∗ B = C + f [ i ] A * B = C + f[ i ] AB=C+f[i]; 所以 f [ i ] = A ∗ B − C f[ i ] = A * B - C f[i]=ABC;由于数比较大,所以直接两边同时取模,但是要保证对于任意 i ! = j , 要 有 f [ i ] ( m o d    p ) ! = f [ j ] ( m o d    p ) i!=j,要有f[i] (mod\; p) !=f[j] (mod\;p) i!=j,f[i](modp)!=f[j](modp)

#include     //思维、数学
#include
#include
using namespace std;
typedef long long LL;
const int N = 2e6+10;
const int mod = 887654321;

LL f[N];
int n,k,t;

int main()
{
	f[0]=1,f[1]=1;
	for(int i=2;i<N;i++) f[i] = (f[i-1]+f[i-2])%mod;
	
    int T; scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        LL a=0,b=0,c=0;
        for(int i=1;i<=n;i++){
        	scanf("%d",&t);
        	a = (a+f[i]*t) % mod;
		}
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
        	scanf("%d",&t);
        	b =(b+f[i]*t) % mod;
		}
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
        	scanf("%d",&t);
        	c = (c+f[i]*t) % mod;
		}
		LL ans = (a*b%mod-c+mod) % mod;
		for(int i=1;i<=n;i++)
        	if(f[i]==ans){
        		printf("%d\n",i);
        		continue;
			}
    }
    return 0;
}

1001 Total Eclipse(并查集 思维)

题意:每次选一个连通块使里面所有点的值减一,当某个点减为零时其点连的所有边都会删去,求多少次操作使所有点变成0。

这题顺着做,就是每次找到最大的连通块,然后-1,之后可能出现某些连接点权值为0断开,变成多个连通块继续做。
因此考虑倒着做,我们发现,每个点作为单独的连通块做出的贡献就是当旁边的点权值为0了,因此将点的权值排序后从头枚举,对于每个点枚举他的邻边,如果邻点的权值大于他,就把他们两个集合合并,答案的贡献就是两个集合父节点的权值差,之后枚举最后父节点是自己的答案加上即可。

#include
#include
#include
using namespace std;
typedef long long LL;
const int N = 1e5+7; 

int p[N],w[N],vis[N];
int fa[N];
vector<int> g[N];

int find(int x){
	if(x!=fa[x]) fa[x] = find(fa[x]);
	return fa[x];
}
bool cmp(int a,int b){
	return w[a]>w[b];
}

int main()
{
	int T;scanf("%d",&T);
	while(T--){
		int n,m;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++) {
			fa[i]=i,p[i]=i,g[i].clear(),vis[i]=0;
			scanf("%d",&w[i]);
		}
		for(int i=1;i<=m;i++){
			int x,y;
			scanf("%d%d",&x,&y);
			g[x].push_back(y);
			g[y].push_back(x);
		}
		sort(p+1,p+n+1,cmp);
		LL ans=0;
		for(int i=1;i<=n;i++){
			for(auto v:g[p[i]]){
				if(w[v] < w[p[i]]) continue;
				int x = find(p[i]),y = find(v);
				if(x!=y){
					fa[y] = x;		//以小权值点为根;
					ans += w[y]-w[x];
				}
			}
		}
		for(int i=1;i<=n;i++) if(fa[i]==i) ans+=w[i];
		printf("%lld\n",ans);
	}
    return 0;
}

你可能感兴趣的:(HDU)