牛客練習賽41 A B C D E

傳送門:https://ac.nowcoder.com/acm/contest/373#question

A. 翻硬幣問題

題解:很明顯如果不能一次拿走,那麼BobBob總是能翻轉其中一枚硬幣來破壞nnmm的奇偶性。

代碼

#include<bits/stdc++.h>
 
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
 
using namespace std;
//1 1 1 1 1
//0 0 0 1 1
//0 1 1 1 1
//
int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
    ios::sync_with_stdio(false); cin.tie(0);
    int n,m;
    int T;
    cin >> T;
    while(T--) {
        cin >> n >> m;
        cout << ((n == m)? "Yes" : "No")<< endl;   
    }
    return 0;
}

B. 666RPG

題意:兩個操作。

  1. 每次將分數加a[i]a[i]
  2. 將當前總分乘以1-1

問:給出序列a[i]a[i],多少種方案使得最後的分數爲666-666

題解dp[i][j]dp[i][j]表示前ii個數可以湊成分數爲jj的方案總數。顯然每次有兩個狀態轉移,也就是dp[i][j]dp[i][j]會從dp[i1][ja[i]]dp[i-1][j - a[i]]dp[i1][j]dp[i -1][-j]轉移過來。因此
dp[i][j]=dp[i1][ja[i]]+dp[i1][j]dp[i][j] = dp[i - 1][j - a[i]] + dp[i -1][-j]
發現這樣會mlemle。再看方程,每次只會從i1i-1轉移過來,因此,滾動數組解決。

代碼

#include<bits/stdc++.h>

#define DEBUG(x) std::cerr << #x << '=' << x << std::endl

using namespace std;
typedef long long LL;
const int N = 300 * 666, mod = 1e8 + 7;
LL dp[2][N * 10];
int a[N];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
    ios::sync_with_stdio(false); cin.tie(0);
    //dp[i][j] = dp[i - 1][j - a[i]] + dp[i - 1][-j]
    int n, cur = 0;
    cin >> n;
    for(int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    int dx = N + 666;
    dp[1][dx] = 1;
    for(int i = 1; i <= n; ++i) {
        for(int j = -N; j <= N; ++j) {
            if(j == 666) continue;
            dp[cur][j + dx] = (dp[cur ^ 1][j - a[i] + dx] + dp[cur ^ 1][-j + dx]) % mod;
        }
        cur ^= 1;
    }
    cout << dp[cur ^ 1][-666 + dx] << endl;
    return 0;
}

C. 抓捕盜竊犯

題解:可以知道會形成很多個環,在環上任意建一點哨卡即可,最終的收益是環上所有點,因此我們預處理出所有連通塊(我這裏用的並查集),然後排序取前mm大的即可。

代碼

#include<bits/stdc++.h>
 
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
 
using namespace std;
const int N = 1E5+10;
typedef long long LL;
int f[N],node[N];
LL a[N], sum[N];
vector<int> E[N];
 
int getf(int v)
{
    if(f[v] == v) return v;
    return f[v] = getf(f[v]);
}
 
void mrg(int u,int v)
{
    int p = getf(u);
    int q = getf(v);
    if(p != q) {
        f[p] = q;
    }
}
vector<LL> value;
int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
    ios::sync_with_stdio(false); cin.tie(0);
    int n,m;
    cin >> n >> m;
    for(int i = 1; i <= n; ++i) {
        cin >> a[i];
        f[i] = i;
    }
    int v;
    for(int i = 1; i <= n; ++i) {
        cin >> v;
        mrg(i,v);
    }
     
    for(int i = 1; i <= n; ++i) {
        E[getf(i)].push_back(a[i]);
    }
    LL ans = 0;
    for(int i = 1; i <= n; ++i) {
        if(f[i] == i) {
            LL SUM = 0;
            for(auto w : E[i]) {
                SUM += w;
            }
            value.push_back(SUM);
        }
    }
    sort(value.begin(),value.end(),greater<LL>());
    for(int i = 0; i < m && i < value.size(); ++i) {
        ans += value[i];
    }
    cout << ans << endl;
    return 0;
}

D. 最小相似度

題意:求max{SIM(si,T)}max\{SIM(s_i,T)\}的最小值,SIM(A,B)SIM(A,B)表示AABB異或後的00的個數。
題解:emmmm,表示fwt就做過一道題,不太會。

但是MM大小隻有2020,狀態只有2202^{20}個,我們考慮給出的nn個串到每個狀態的距離的最小距離,串aa到串bb的花費爲改變的位數,我們讓這個最小距離最大化,然後用mm減去這個最大化的最小距離,就是這nn個串與串TT最大距離的最小值。但是這樣做是O(n2m)O(n\cdot 2 ^ m)的,因此用多源bfsbfs處理即可,複雜度爲節點個數,即O(n+2m)O(n + 2^m)

代碼

#include<bits/stdc++.h>

#define DEBUG(x) std::cerr << #x << '=' << x << std::endl

using namespace std;
int dis[1 << 21];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
    ios::sync_with_stdio(false); cin.tie(0);
	int n,m;
	memset(dis, -1, sizeof dis);
	string s;
	cin >> n >> m;
	queue<int> q;
	for(int i = 0; i < n; ++i) {
		cin >> s;
		int t = 0;
		for(int j = 0; j < m; ++j) {
			t |= (1 << j) * (s[j] == '1');
		}
		if(dis[t] == -1) {
			dis[t] = 0;
			q.push(t);
		}
	}
	int ans = 0;
	while(!q.empty()) {
		int cur = q.front(); q.pop();
		ans = max(ans, dis[cur]);
		for(int i = 0; i < m; ++i) {
			if(dis[cur ^ (1 << i)] == -1) {
				dis[cur ^ (1 << i)] = dis[cur] + 1;
				q.push(cur ^ (1 << i));
			}
		}
	}
	cout << m - ans << endl;
    return 0;
}

E. 球的體積並

題解:正好寒假秦皇島camp做過一道球的體積交的題,嘿嘿。直接隨便copy了一份板子就過了~
判斷一下兩個球是相交還是相離還是相切即可。

代碼

#include<bits/stdc++.h>
using namespace std;
double Pow(double x){ return x*x; }
double san(double x){ return x*x*x; }
const double PI = acos(-1);

struct node {
    double x, y, z, r;

    void get() { scanf("%lf%lf%lf%lf", &x, &y, &z, &r); }

    double dis(node a) {
        return sqrt(Pow(x - a.x) + Pow(y - a.y) + Pow(z - a.z));
    }

    double get_aera(node a) {
        double d = dis(a);
        double x1 = (a.r * a.r - r * r + d * d) / 2 / d;
        double x2 = d - x1;
        double h1 = r - x2;
        double h2 = a.r - x1;
        return PI / 3 * (3 * r - h1) * h1 * h1
               + PI / 3 * (3 * a.r - h2) * h2 * h2;
    }
}a[2];
int main() {
    a[0].get();
    a[1].get();
    double ans = 0;
    double p = 4.0 / 3 * PI * san(a[1].r), q = 4.0 / 3 * PI * san(a[0].r);
    if (a[0].dis(a[1]) <= fabs(a[0].r - a[1].r)) {
        ans = max(p, q);
    } else if (a[0].dis(a[1]) >= a[0].r + a[1].r) {
        ans = p + q;
    } else {
        ans = p + q - a[0].get_aera(a[1]);
    }
    printf("%.7f\n", ans);
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章