“中国东信杯”广西大学第三届程序设计竞赛

本来是当做准备校赛前的信心赛打的,结果还是有好几道看了题解才明白.....加油吧~

A A++++++++++++++++++

大意:

对于给出的n个title中,每能组成一对<national,international>,那么竞赛的等级就可以在A的基础上增加一个+,问最后的竞赛等级

思路:

取min即可

#include<iostream>
using namespace std;
int main(){
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        string s;
        int num1=0,num2=0;
        for(int i=0;i<n;i++){
            cin>>s;
            if(s=="national") num1++;
            if(s=="international") num2++;
        }
        cout<<"A";
        for(int i=0;i<min(num1,num2);i++)
        {
            cout<<"+";
        }
        cout<<endl;
    }
    return 0;
}

B GDP Carry

大意:

给出n个数,Antinomy先手,需要取连续的一段和为奇的数,小西后手,需要取连续的一段和为偶的数,无法继续则判定为输。问在最佳策略下谁会赢

思路:

如果n个数的和为奇,那么Antinomy先手直接胜利,如果和为偶,且存在奇数,那么Antinomy可以先取一个奇数,使得剩下的和为奇数(偶数-奇数=奇数),此时小西由于只能选偶数,所以小西必然只能给Antinomy留下奇数,所以又转化为了Antinomy必赢的局面,如果和为偶且不存在奇数,那么小西必赢,因为Antinomy先手没有数可以取。

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
long long a[N];
int main(){
        int n;
        cin>>n;
        int f=0;
        long long sum=0;
        for(int i=0;i<n;i++){
            cin>>a[i];
            sum+=a[i];
            if(a[i]%2) f++;
        }
        if(sum%2==0&&f==0) cout<<"XiJam"<<endl;
        else cout<<"Antinomy"<<endl;
    return 0;
}

C Interpretability

大意:

给出n个数字(f_i)代表(2^i)的数量,问由这些数最多能组成多少个三角形

思路:

由于都是(2^i),所以只可能是三个相同的数或者两个相同的数加一个较小的数。所以从小到大扫一遍,看将(f_i)拿出一对一对的情况下,和前面(包括自己)单个的边能组成三角形的数量,如果剩下了,就将其作为单个的边记录下来。

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
int const MAXN = 4e5 + 10;
LL n, m, T, a[MAXN];

int main() {
    cin >> n;
    for (int i = 1; i <= n; ++i) scanf("%lld", a + i);
    LL pair = 0, single = 0, res = 0;
    LL tmp = 0, minv = 0;
    for (int i = 1; i <= n; ++i) {
        LL pair_cnt = a[i] / 2;
        LL single_cnt = a[i] % 2;
        tmp = pair_cnt;
        single += single_cnt;
        minv = min(pair_cnt, single);
        res += minv;
        LL cnt3 = (pair_cnt - minv) * 2 / 3;
        res += cnt3;
        single -= minv, single += (pair_cnt - minv) * 2 % 3;
    }
    cout << res;
    return 0;
}

D Batch Normalization 1D

大意:

模拟题

思路:

大模拟题,不想做了,piao的代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 50;
const int INF = 0x3f3f3f3f;
const int mod = 1000000007;
LL powmod(LL a, LL b) { LL res = 1; a %= mod; assert(b >= 0); for (; b; b >>= 1) { if (b & 1) res = res * a % mod; a = a * a % mod; } return res; }

int n, c, n_batch;
double eps, momentum;
double X[N][N];
double Gamma[N];
double Beta[N];
double moving_mean[N];
double moving_var[N];
double mu[N];
double var[N];
double var_tmp[N][N];
double X_hat[N][N];
double out[N][N];

int main() {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> n >> c >> n_batch >> eps >> momentum;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= c; j++) {
			cin >> X[i][j];
		}
	}
	for (int i = 1; i <= c; i++) {
		cin >> Gamma[i];
	}
	for (int i = 1; i <= c; i++) {
		cin >> Beta[i];
	}
	for (int i = 1; i <= c; i++) {
		cin >> moving_mean[i];
	}
	for (int i = 1; i <= c; i++) {
		cin >> moving_var[i];
	}

	for (int i = 1; i <= c; i++) { //cal mu
		double sum = 0.0;
		for (int j = 1; j <= n; j++) {
			sum += X[j][i]; //order!
		}
		mu[i] = sum / n;
	}
	//cal var
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= c; j++){
			var_tmp[i][j] = pow((X[i][j] - mu[j]), 2);
		}
	}
	for (int i = 1; i <= c; i++) {
		double sum = 0.0;
		for (int j = 1; j <= n; j++) {
			sum += var_tmp[j][i]; //order!
		}
		var[i] = sum / n;
	}
	while (n_batch--) {
		for (int i = 1; i <= n; i++) { //cal X_hat
			for (int j = 1; j <= c; j++) {
				X_hat[i][j] = (X[i][j] - mu[j]) / sqrt(var[j] + eps);
			}
		}
		for (int i = 1; i <= c; i++) {
			moving_mean[i] = moving_mean[i] * momentum + (1.0 - momentum) * mu[i];
		}
		for (int i = 1; i <= c; i++)  {
			moving_var[i] = moving_var[i] * momentum + (1.0 - momentum) * var[i];
		}
		for (int i = 1; i <= n; i++) { //cal out
			for (int j = 1; j <= c; j++) {
				out[i][j] = X_hat[i][j] * Gamma[j] + Beta[j];
			}
		}
	}
	//last
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= c; j++) {
			X_hat[i][j] = (X[i][j] - moving_mean[j]) / sqrt(moving_var[j] + eps);
		}
	}
	for (int i = 1; i <= n; i++) { //cal out
		for (int j = 1; j <= c; j++) {
			out[i][j] = X_hat[i][j] * Gamma[j] + Beta[j];
		}
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= c; j++) {
			cout << out[i][j] << " ";
		}
		cout << endl;
	}
	return 0;
}

E Antinomy与黑风海

大意:

有向图,从点1出发,每次去其他的点做任务,做完回到1点后才能去下一个点做任务,问做完全部任务需要走多远

思路:

很容易看出来前去做任务就是求点1到其他所有点的距离即可,那么怎么求回来的距离呢?直接把每条边反向,重新建一遍图即可

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<LL, int> PII;
int const MAXN = 1e6 + 10, MAXM = 2 * MAXN;
int n, m, T, h[MAXN], e[MAXM], ne[MAXM], idx, w[MAXM], st[MAXN];
LL dis[MAXN];
struct Edge {
    int u, v, c;
}edge[MAXM];

void add(int a, int b, int c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

void dijkstra() {
    memset(dis, 0x3f, sizeof dis);  // 初始化距离为无穷
    priority_queue<PII, vector<PII>, greater<PII> > q;  // 定义一个按照距离从小到大排序的优先队列,第一维:距离,第二维:点
    dis[1] = 0;  // 一开始源点距离为0
    q.push({0, 1});  // 把源点信息放入队列
    while (q.size()) {  // 每个点只出入队列一次
        auto t = q.top();
        q.pop();
        
        LL distance = t.first;
        int ver = t.second;  // 最小距离和相对应的点
        if (st[ver]) continue;  // 这个操作保证每个点只出入队一次,因为队列里面可能会出现{dis1[3], 3}, {dis2[3], 3}的情况,这样保证dis1[3]<dis2[3]时,3号点只进出入队一次
        st[ver] = 1;  // 标记,因为dijkstra的贪心策略保证每个点只需要进出队一次
        
        for (int i = h[ver]; ~i; i = ne[i]) {  // 遍历ver的邻接点
            int j = e[i];
            if (dis[j] > distance + (LL)w[i]) {
                dis[j] = distance + (LL)w[i];
                q.push({dis[j], j});  // 这里不需要判断st,因为一旦更新发现更小必须放入队列
            }
        }
    }
}

int main() {
    memset(h, -1, sizeof h);
    idx = 0;
    cin >> n >> m;
    for (int i = 1; i <= m; ++i) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        edge[i] = {a, b, c};
        add(a , b, c);
    }
    dijkstra();
    LL res = 0;
    for (int i = 1; i <= n; ++i) {
        h[i] = -1;
        st[i] = 0;
        if (i != 1) res += dis[i];
    }
    idx = 0;
    for (int i = 1; i <= m; ++i) {
        int a = edge[i].u, b = edge[i].v, c = edge[i].c;
        add(b, a, c);
    }
    dijkstra();
    for (int i = 2; i <= n; ++i) {
        res += dis[i];
    }
    cout << res;
    return 0;
}

F Antinomy与紫水宫

大意:

给出一个树,树上每对距离小于3的节点颜色都不能相同,现在有m种颜色,问有多少种涂色方法

思路:

树形dp,首先固定每个节点与其父节点的颜色,那么子节点的颜色数利用组合数可以算出来(A_{m=2}^{子节点数量}),然后向父节点传递即可。注意根节点处因为没有父节点所以要单独写

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 5, mod = 1e9 + 7;
typedef long long LL;
int n, m;
vector<int> mp[N];
int fact[N], infact[N];

LL qmi(LL a, LL k, LL p) {
    LL res = 1;
    while (k) {
        if (k & 1) res = res * a % p;
        k >>= 1;
        a = a * a % p;
    }
    return res;
}

// 预处理
void init() {
    fact[0] = infact[0] = 1;
    for (int i = 1; i < N; ++i) {
        fact[i] = (LL)fact[i - 1] * i % mod;
        infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
    }
}

int Cnm(int a, int b) {
    return (LL)fact[a] * infact[b] % mod * infact[a - b] % mod;
}

int res = 1;
void dfs(int now, int fa) {
    res = (LL)res * Cnm(m - 2, mp[now].size() - 1) % mod *
          fact[mp[now].size() - 1] % mod;  //求Anm;
    for (int i = 0; i < mp[now].size(); i++) {
        int ne = mp[now][i];
        if (ne == fa) continue;
        dfs(ne, now);
    }
}
int main() {
    cin >> n >> m;
    init();
    for (int i = 0; i < n - 1; i++) {
        int x, y;
        cin >> x >> y;
        mp[x].push_back(y);
        mp[y].push_back(x);
    }
    res = (LL)res * Cnm(m, mp[1].size() + 1) % mod * fact[mp[1].size() + 1] % mod;
    for (int i = 0; i < mp[1].size(); i++) {
        dfs(mp[1][i], 1);
    }
    cout << res << endl;
    return 0;
}

G Antinomy与伊修加德

大意:

Antinomy想买一些盘子来装拉拉肥,这样可以打包卖出去,每个拉拉肥不能拆开卖。

每个拉拉肥都有售价,第i个拉拉肥卖出去后的售价是(p_i)金币。

每个盘子也需要花钱买,第iii个盘子需要花(c_i)金币,能装(b_i)个拉拉肥。

每个拉拉肥可以卖也可以不卖,但卖就必须要放在一个盘子里。Antinomy的利润就是卖出去的拉拉肥售价总和,减去盘子的花费。

思路:

类似01背包的问题,每个盘子取或不取,价值就是拉拉肥的收益-盘子价格,体积就是拉拉肥的个数,注意要先将拉拉肥按照价值排序,因为拉拉肥的体积相同,那么肯定是优先卖价值高的

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
typedef long long LL;
int n, m, p[N], b[N], c[N], pre[N],dp[N];
int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> p[i];
    }
    sort(p + 1, p + 1 + n, greater<int>());
    for (int i = 1; i <= n; i++) {
        pre[i] = pre[i - 1] + p[i];
    }
    for (int i = 0; i < m; i++) {
        cin >> b[i] >> c[i];
    }
    int res = 0;
    for (int i = 0; i < m;i++){
        for (int j = n; j >= 0;j--){
            if(j>=b[i])
                dp[j] = max(dp[j], dp[j - b[i]] + pre[j] - pre[j - b[i]] - c[i]);
            else
                dp[j] = max(dp[j], pre[j] - c[i]);
            res = max(res, dp[j]);
        }
    }
    cout << res << endl;
    return 0;
}

H Antinomy与太阳神草原

大意:

思路:

原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/14179457.html