2021中国大学生程序设计竞赛部分题解(CCPC)- 网络选拔赛(重赛)

文章目录


一、1002 Kanade Doesn’t Want to Learn CG

简单数学问题:判断位置即可

#include <bits/stdc++.h>
#define MaxN 0x3f3f3f3f
#define MinN 0xc0c0c0c0
#define bug(x) cout << #x"=" << x << endl;
#define BUG(a,b) cout << #a"=" << a << " " << #b"=" << b << endl;
#define ALL(a) a.begin(), a.end()
#define rep1(i,a,b) for(int i=(a);i<=(b);i++)
#define per1(i,a,b) for(int i=(a);i>=(b);i--)
#define rep2(i,a,b) for(int i=(a);i<(b);i++)
#define per2(i,a,b) for(int i=(a);i>(b);i--)
#define mset(a,b) memset(a,b,sizeof(a))
#define sz(a) (int)a.size()
#define EPS 1e-9
#define MAX(a,b) (((a)>(b)? (a):(b)))
#define MIN(a,b) (((a)>(b)? (b):(a)))
#define buff ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define INF 0x3f3f3f3f
#define pb push_back
#define fi first
#define se second
#define mp make_pair
#define pf(x) printf("%d\n",x);
#define sf(x) scanf("%d",&x);

using namespace std;

void solve(){
	int a,b,c;
	scanf("%d%d%d",&a,&b,&c);
	
	double x0,x1,y0,y1,y2;
	scanf("%lf%lf%lf%lf%lf",&x0,&x1,&y0,&y1,&y2);
	
	double x = 0.0;
	x = (-sqrt(b*b-4*a*(c-y0))-b)/(2*a);               
	// 这里注意a是负数:取哪个根的时候要抉择一下. 
	
//	cout << "x=" << x << " x0=" << x0 << " x1=" << x1 << endl;
	
	if(x>x0 && x1>x)	puts("YES");
	else if(x<=x0) 		puts("NO");
	else{
		double yy = a*x1*x1+b*x1+c;
		
		if(yy<=y2){
			if(2*x1-x>x0 && 2*x1-x<x1){
				puts("YES");
			}else{
				puts("NO");
			}
		}else{
			puts("NO");
		}
	}
}

int main()
{
	//buff;
	int t;
	scanf("%d",&t);
	while(t--){
		solve();
	} 

	return 0;
}


二、1004 Primality Test

签到题。
通过水几组样例可以发现规律:当 x>1 时输出NO,当x=1时输出YES.

正经分析:通过观察发现,f(x)和f(f(x))是连续的质数,质数一定是奇数,故g(x)一定是整数.(从这里就可以看出2比较特殊(因为2是偶数))。假设g(x)是个质数,则g(x)一定在f(x)和f(f(x))之间,与观察矛盾,故g(x)不可能是质数。

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

int main()
{
	int t;
	scanf("%d",&t);
	long long x;
	while(t--){
		scanf("%lld",&x);
		
		if(x==1)	puts("NO");
		else	puts("YES");
	}
	
	return 0;
}

三、1005 Monopoly

维护一种数据结构…(kungeyyds)

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll p = 998244353;

ll a[100010];
struct node {
    ll u, x, pos;
    friend bool operator<(node s1, node s2) {
        if(s1.u == s2.u) return s1.x < s2.x;
        return s1.u < s2.u;
    }
} q[100010];
#define sangkun
int main() {
	#ifdef sangkun
	freopen("in.txt", "r", stdin);
	#endif
    int t;
    cin >> t;
    while(t--) {
        int n, m;
        cin >> n >> m;
        ll sum = 0;
        int op = 0;
        map<ll, map<ll, bool>>vis;
        for(int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
            sum += a[i];
        }
        if(sum == 0) {
            map<ll, int>ans;
            for(int i = 1; i <= n; i++) {
                a[i] += a[i - 1];
                if(!ans[a[i]]) ans[a[i]] = i;
            }
            while(m--) {
                ll x;
                cin >> x;
                if(x == 0) {
                    printf("0\n");
                } else if(ans[x]) {
                    printf("%d\n", ans[x]);
                } else printf("-1\n");
            }
            continue;

        }
        int ok=0;
        if(sum < 0) {
            for(int i = 1; i <= n; i++) {
                a[i] = -a[i];
            }
            sum = -sum;
            ok=1;
        }
        q[++op] = {0, 0, 0};
        vis[0][0] = 1;
        for(int i = 1; i <= n; i++) {
            a[i] += a[i - 1];
            ll u = abs(a[i]) % sum;
            ll x = a[i] / sum;
            if(a[i] < 0) u = sum - u, x--;
            if(vis[u][x]) continue;
            vis[u][x] = 1;
            q[++op] = {u, x, i};
        }
        sort(q + 1, q + 1 + op);
//        for(int i=1;i<=op;i++) cout<<q[i].u<<" "<<q[i].x<<" "<<q[i].pos<<endl;
        while(m--) {
            ll x;
            cin >> x;
            if(ok) x=-x;
            ll u = abs(x) % sum, y = x / sum;
            if(x < 0) u = sum - u, y--;
            ll l = 1, r = op, ansl = op + 1, ansr = 0, ans = 0;
            while(l <= r) {
                int mid = (l + r) >> 1;
                if(q[mid].u < u) l = mid + 1;
                else r = mid - 1, ansl = mid;
            }
            l = 1, r = op;
            while(l <= r) {
                int mid = (l + r) >> 1;
                if(q[mid].u <= u) l = mid + 1, ansr = mid;
                else r = mid - 1;
            }
            if(q[ansl].u != u) {
                printf("-1\n");
                continue;
            }
            l = ansl, r = ansr;
            while(l <= r) {
                int mid = (l + r) >> 1;
                if(q[mid].x <= y) l = mid + 1, ans = mid;
                else r = mid - 1;
            }
            if(ans == 0) {
                printf("-1\n");
                continue;
            }
            ans = (y - q[ans].x) * n + q[ans].pos;
            cout << ans << endl;
        }
    }
    return 0;
}

四、1006 Nun Heh Heh Aaaaaaaaaaa

DP问题:定义dp(i,j) 表示前i个数中匹配到第j位的方案数.
dp(i,j) = dp(i-1,j) + (if(匹配) +1);
dp[i][j] = (dp[i-1][j] + dp[i-1][j-1]*(s[i]==str[j])) % MOD;

dp(i,9)*后缀a的贡献数即为答案.

后缀a的方案数:2的n次方-1(由二项式定理推出)
处理2的n次方:使用快速幂或者使用左移运算符(1<<i);

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#define bug(x) cout << #x"=" << x << endl;
#define BUG(a,b) cout << #a"=" << a << " " << #b"=" << b << endl;

using namespace std;

typedef long long ll;
const int N = 100010;
const int MOD = 998244353;

ll mod_power(ll a,ll n,ll mod){ll res = 1;while(n){if(n&1) res = res*a%mod;n >>= 1;a = a*a%mod;}return (res-1);}

ll dp[N][10];
char s[N];

void solve(){
	char str[] = " nunhehheh";
	ll a[N];

	scanf("%s",s+1);
	int len = strlen(s+1);
//	cout << len << endl;
	
	a[len+1] = 0;
	for(int i=len;i>=1;i--){
		a[i] = a[i+1] + (s[i]=='a');
	}
	
	ll ans = 0;
	for(int i=1;i<=len;i++){
		for(int j=1;j<=9;j++){
			if(j==1)	dp[i][j] = dp[i-1][j] + (s[i]==str[j]);
			else if(j==9)	dp[i][j] = dp[i][j-1]*(s[i]==str[j]);         // 这里出现问题. 
			else    dp[i][j] = dp[i-1][j] + dp[i-1][j-1]*(s[i]==str[j]);
		}
		
		if(dp[i][9]){
			ans = (ans + (dp[i][9]*mod_power(2,a[i+1],MOD))%MOD)%MOD;
			// ans = (ans + (dp[i][9]%MOD*((1<<a[i+1])-1)%MOD)%MOD)%MOD; 使用左移运算符计算.
		}
	}
	
	printf("%lld\n",ans);
}

int main()
{
	int t;
	scanf("%d",&t);
	while(t--){
		solve();
	}
	
	return 0;
}

五、1010 Bigraph Extension

(kungeyyds)

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll p = 998244353;

int f[1010][2];
int pre[2010];
int tmp(int x) {
    if(x == pre[x]) return x;
    return pre[x] = tmp(pre[x]);
}
int n, m;
bool add(int x, int y) {
    y += n;
    int A = tmp(x);
    int B = tmp(y);
    if(A == B) return false;
    pre[A] = B;
    return true;
}

int main() {
    int t;
    cin >> t;

    while(t--) {
        cin >> n >> m;
        map<int, map<int, int>>vis;
        vector<pair<int, int>>ans;
        set<int>s;
        for(int i = 1; i <= n; i++) {
            pre[i] = i;
            pre[i + n] = i+n;
            f[i][0] = 0;
            f[i][1] = 0;
            s.insert(i);
        }
        for(int i = 1; i <= m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            add(u, v);
            f[u][0]++;
            f[v][1]++;
            if(f[v][1] == 2) s.erase(v);
        }

        if(m == 0) {
            f[1][0]++;
            f[1][1]++;
            add(1, 1);
            ans.push_back({1, 1});
        }
        for(int i = 1; i <= n; i++) {
            while(f[i][0] != 2 && ans.size() + m != 2 * n - 1) {
                f[i][0]++;
                for(auto j : s) {
//                    cout << tmp(i) << ":" << tmp(j) << endl;
                    if(!add(i, j))  continue;
                    f[j][1]++;
                    ans.push_back({i, j});
//                    cout << i << "==" << j << endl;
                    if(f[j][1] == 2)s.erase(j);
                    break;
                }
            }
        }
        std::cout << q0 << ' '
        int q1 = 0, q2 = 0;
        for(int i = 1; i <= n; i++) {
            if(f[i][0] == 1) q1 = i;
            if(f[i][1] == 1) q2 = i;
        }
        ans.push_back({q1, q2});
        cout << ans.size() << endl;
        for(auto i : ans) printf("%d %d\n", i.first, i.second);

    }
    return 0;
}

六、1011 Jumping Monkey

先排序然后从小到大枚举;每次把当前点作为并查集的根;然后遍历它的儿子 ;只考虑权值比它小的;那么儿子所在的集的根能到的第一个点就是当前点;这样去求每个点能到的第一个比它大的点;然后倒序去求答案;答案就是能到的第一个点的答案+1.

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll p = 998244353;

int u[100100], v[100100];
int a[100100], b[100100];
vector<int>g[100100];
int ans[100010];
int pre[100010];
int tmp(int x) {
    if(x == pre[x]) return x;
    return pre[x] = tmp(pre[x]);
}
int main() {
    int t;
    cin >> t;
    while(t--) {
        int n;
        scanf("%d", &n);
        for(int i = 1; i < n; i++) {
            scanf("%d%d", &u[i], &v[i]);
        }
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            b[i] = a[i];
            g[i].clear();
            ans[i] = 0;
            pre[i] = i;
        }
        sort(b + 1, b + 1 + n);
        for(int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + 1 + n, a[i]) - b;
        for(int i = 1; i <= n; i++) {
            u[i] = a[u[i]];
            v[i] = a[v[i]];
            g[u[i]].push_back(v[i]);
            g[v[i]].push_back(u[i]);
        }
        for(int i = 1; i <= n; i++) {
            for(auto j : g[i]) {
                if(j < i) {
                    int A = tmp(j);
                    if(A == i) continue;
                    pre[A] = i;
                    ans[A] = i;
                }
            }
        }
        for(int i = n; i >= 1; i--) {
            ans[i] = ans[ans[i]];
            ans[i]++;
        }
        for(int i = 1; i <= n; i++) printf("%d\n", ans[a[i]]);
    }
}

上一篇:2021.11.3 CCPC桂林 打铜总结


下一篇:软件学院CCPC选拔赛题解