首页 > 其他分享 >The 2021 China Collegiate Programming Contest (Harbin) JBEIDG

The 2021 China Collegiate Programming Contest (Harbin) JBEIDG

时间:2023-09-27 23:24:13浏览次数:49  
标签:10 cnt Contest int suf ll Programming Collegiate ++

The 2021 China Collegiate Programming Contest (Harbin)

目录

VP概况

队友不应该写签到,签到应该我来写,以至于多了 \(2\) 罚时,后面的题放心交给队友就好。
image
image

J - Local Minimum

问矩阵中有多少个元素 \(A_{i,j}\) 同时是第 \(r\) 行,第 \(c\) 列上的最小元素

\(n = 1000\) 直接暴力

const int N = 1e3 + 10;
ll a[N][N], n, m, res, r[N], c[N];
void solve()
{
	cin>>n>>m;
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
			cin>>a[i][j];

	memset(r, 0x3f, sizeof r);
	memset(c, 0x3f, sizeof c);
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
			r[i] = min(a[i][j], r[i]);
	for(int j = 1; j <= m; j++)
		for(int i = 1; i <= n; i++)
			c[j] = min(a[i][j], c[j]);	
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
			if(a[i][j] == r[i] && a[i][j] == c[j])
				res++;
	cout<<res<<'\n';
}

B - Magical Subsequence

问子序列第 \(2 \times i\) 元素和 第\(2 \times i - 1\) 位元素的和为 \(X\) 时,子序列的最大长度是?

定义状态 \(f_{i,j}\) ,表示第 \(i\) 位,元素和为 \(j\) 的子序列最大长度

预处理 \(suf_{i,j}\) 表示第 \(i\) 位,后缀中值为 \(k\) 的元素位置

转移方程:

\[f_{suf_{i,j-a_i},j} = f_{i-1,j} + 2 \]

const int N = 1e5 + 10;
 
int f[N][210];
int a[N], suf[N][110];
 
void solve()
{
	ll n;
	cin>>n;
	for(int i = 1; i <= n; i++)
		cin>>a[i];
	memset(suf, -1, sizeof suf);
	for(int i = n; i >= 1; i--)
	{
		for(int j = 1; j <= 100; j++)
			suf[i][j] = suf[i + 1][j];
		if(i + 1 <= n)
			suf[i][a[i + 1]] = i + 1;
	}
	int res = 0;
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= 200; j++)
			f[i][j] = max(f[i - 1][j], f[i][j]);
		for(int j = a[i] + 1; j <= 200; j++)
		{
			if(j - a[i] > 100)	break;
			int k = j - a[i];
			if(suf[i][k] == -1)	continue;
			f[suf[i][k]][j] = max(f[i - 1][j] + 2, f[suf[i][k]][j]);
			res = max(f[suf[i][k]][j], res);
		}
	}
	cout<<res<<'\n';
}

E - Power and Modulo

考虑到 \(a_i \leq 10^9\),那么对于取模来说,在 \(n\) 足够大的情况下,一定存在

\(2^{i - 2} \% m= 2^{i - 2}\)

\(2^{i - 1} \% m= a_i\)

const int N = 1e5 + 10;
ll a[N], n;
ll bmi[N];
void solve()
{
	cin>>n;
	for(int i = 1; i <= n; i++)
		cin>>a[i];
	bmi[1] = 1;	
	for(int i = 2; i <= 60; i++)
		bmi[i] = bmi[i - 1] * 2;
	ll m = -1;
 
	for(int i = 1; i <= n; i++)
	{
		// cout<<a[i]<<" "<<bmi[i]<<'\n';
		if(a[i] == bmi[i])
			continue;
		else
		{
			m = bmi[i] - a[i];
			break;
		}
	}
	// cout<<m<<" ";
	if(m == -1)
	{
		cout<<-1<<'\n';
		return;
	}
	bool ok = true;
	ll base = 1 % m;
	for(int i = 1; i <= n; i++)
	{
	 	if(base != a[i])
			ok = false;
		base *= 2;
		base %= m;
	}
	if(ok)
		cout<<m<<'\n';
	else
		cout<<-1<<'\n';
 
}

I - Power and Zero

发现各个二进制位的有多少个,若满足 \(cnt_0 \geq cnt_1 \geq \dots \geq cnt_{32}\) ,则答案最优,不断去调整即可

const int N = 2e5 + 10;
 
int cnt[40];
void solve()
{       
    memset(cnt, 0, sizeof cnt);
    int n;  cin>>n;
    for(int i = 1; i <= n; i++)
    {
        int x;  cin>>x;
        int t = 0;
        while(x)
        {
            cnt[t++] += (x % 2);
            x /= 2;
        }
    }
    while(1)
    {
        bool ok = false;
        for(int i = 1; i <= 32; i++)
        {
            if(cnt[i] > cnt[i - 1])
            {
                ok = true;
                cnt[i]--;
                cnt[i - 1] += 2;
                break;
            }
        }
        if(!ok)
            break;
    }
    cout<<cnt[0]<<'\n';
    return;
}

D - Math master

用二进制数 \(S\) 表示分子剩余部分,我们从低位去检查分母即可

#define int __int128
#define ll __int128
 
using namespace std;
 
inline __int128 read(){__int128 x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-'){f=-1;}ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
inline void write(__int128 x){if (x < 0){putchar('-');x = -x;}if (x > 9) write(x / 10);putchar(x % 10 + '0');}
ll a[50], b[50], c[50];
void solve()
{       
    ll p, q;    
    // cin>>p>>q;
    p = read(), q = read();
    int n = 0, m = 0;
    __int128 t = p;
    while(t)    a[n++] = t % 10, t /= 10;
    t = q;
    while(t)    b[m++] = t % 10, t /= 10;
    for(int S = 0; S < (1 << n); S++)
    {
        ll tp = 0, cnt = 0, d[11];
        memset(d, 0, sizeof d);
        for(int i = n - 1; i >= 0; i--)
            if((S >> i) & 1)
                cnt++, tp = tp * 10 + a[i];
            else    d[a[i]]--;
        __int128 tq =(__int128)tp * q;
        if(tq % p != 0 || tp == 0)  continue;
        tq /= p;
        t = tq;
        int j = 0;
        for(int i = 0; i < m; i++)
            if(b[i] == t % 10)
                j++, t /= 10;
            else 
                d[b[i]]++;
        bool ok = true;
        for(int i = 0; i <= 9; i++)
            if(d[i] != 0)   ok = false;
        if(ok && t == 0 && tq != 0 && tp != 0)
            q = min(q, (ll)tq), p = min(p, (ll)tp);                
    }
    write(p);   cout<<" ";  write(q);
    cout<<'\n';
    return;
}

G - Damaged Bicycle

\(P_S\) 记录集合内单车都是坏的

官方题解:

\(f_{i,S}\) 为访问 \(S\) 集合内的单车,最终停在 \(i\) 号点的最小期望时间,访问 \(i\) 之前就找到了好单车、\(i\) 是第一辆好 单车、\(i\) 还是坏的。

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 1e5 + 10;
int t, r;
int n, m;
vector<pair<int, int>> e[N];
int k;
int pos[N];
bool vis[N];
double p[20];
int d[20][N];
void dij(int id, int start)
{
    priority_queue<pair<int,int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
    memset(vis, false, sizeof vis);
    for(int i = 1; i <= n; i++)
        d[id][i] = 1e9;
    d[id][start] = 0;
    q.push({0, start});
    while(q.size() >= 1)
    {
        auto t = q.top();       q.pop();
        int u = t.second;
        if(vis[u])   continue;
        vis[u] = true;
        for(auto [v, w] : e[u])
        {
            if(d[id][v] > d[id][u] + w)
            {
                d[id][v] = d[id][u] + w;
                q.push({d[id][v], v});
            }
        }
    }
}
double f[20][1 << 20];
double P[1 << 20];
void solve()
{
    cin>>t>>r;
    cin>>n>>m;
    for(int i = 1; i <= m; i++)
    {
        int u, v, w;    
        cin>>u>>v>>w;
        e[u].push_back({v, w});
        e[v].push_back({u, w});
    }
    cin>>k;
    p[0] = 1.0;
    pos[0] = 1;
    for(int i = 1; i <= k; i++)
    {
        cin>>pos[i]>>p[i];
        p[i] = p[i] / 100;
        if(pos[i] == 1)
        {
            p[0] = p[i]; 
            i--, k--;
        }
    }
    for(int i = 0; i <= k; i++)
        dij(i, pos[i]);

    if(d[0][n] >= 1e9)
    {
        cout<<-1<<'\n';
        return;
    }
    double res = p[0] * d[0][n] / t + (1.0 - p[0]) * d[0][n] / r;
    for(int S = 1; S < (1 << k); S++)
    {
        P[S] = p[0];
        for(int j = 0; j < k; j++)
            f[j][S] = 1e15;
        for(int j = 0; j < k; j++)
            if((S >> j) & 1) 
                P[S] *= p[j + 1];
    }
    for(int j = 0; j < k; j++)
    {
        f[j][1 << j] = p[0] * d[0][pos[j + 1]] / t;
        f[j][1 << j] += (1 - p[0]) * d[0][n] / r;
        f[j][1 << j] += p[0] * (1 - p[j + 1]) * d[j + 1][n] / r;
        res = min(f[j][1 << j] + P[1 << j] * d[j + 1][n] / t, res);
    }

    for(int S = 1; S < (1 << k); S++)
    {
        for(int i = 0; i < k; i++)
        {
            if(((S >> i) & 1) == 0) continue;
            for(int j = 0; j < k; j++)
            {
                if(((S >> j) & 1) == 0 || i == j) continue;
                f[i][S] = min(f[j][S ^ (1 << i)] + P[S ^ (1 << i)] * d[j + 1][pos[i + 1]] / t, f[i][S]);
            }
            f[i][S] += P[S ^ (1 << i)] * (1 - p[i + 1]) * d[i + 1][n] / r;
            res = min(f[i][S] + P[S] * d[i + 1][n] / t, res);
        }
    }
    cout<<fixed << setprecision(10) <<res<<'\n';
    // printf("%.10lf\n", res);
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    solve();
}

标签:10,cnt,Contest,int,suf,ll,Programming,Collegiate,++
From: https://www.cnblogs.com/magicat/p/17734624.html

相关文章

  • AtCoder Regular Contest 127 F ±AB
    洛谷传送门AtCoder传送门非常妙的题。先直观感受一下,显然当\(M\)大到一定程度后,\([0,M]\)的所有数都能被取到。考虑\(V\getsV+Ax+By\),其中\(V+Ax+By\in[0,M]\)。如果\(x,y\)都是正数显然可以取到。如果一正一负,比如\(x>0,y\le0\),那可以先把\(V\)......
  • KEYENCE Programming Contest 2019
    A-Beginning排序以后判断一下是否为\(1,4,7,9\)即可。#include<iostream>#include<cstdio>#include<algorithm>usingnamespacestd;constintN=10;inta[N];intmain(){ for(inti=1;i<=4;i++) scanf("%d",&a[i]); sort(a+1,a+4+1......
  • NIKKEI Programming Contest 2019
    A-Subscribers最小值为\(\min(A,B)\),最大值为\(\max(A+B-n,0)\)。#include<iostream>#include<cstdio>usingnamespacestd;intn,A,B;intmain(){ scanf("%d%d%d",&n,&A,&B); printf("%d%d",min(A,B),max(A+B-n,0......
  • Dwango Programming Contest V
    A-Thumbnail直接按照题意模拟。。。#include<iostream>#include<cstdio>#include<cmath>usingnamespacestd;constintN=105;intn;inta[N];intmain(){ scanf("%d",&n); for(inti=1;i<=n;i++) scanf("%d",&a[i])......
  • M-SOLUTIONS Programming Contest
    A-SumofInteriorAngles答案为\(180(n-2)\)。#include<iostream>#include<cstdio>usingnamespacestd;intn;intmain(){ scanf("%d",&n); printf("%d",180*(n-2)); return0;}B-Sumo判断一下x的个数是否小于等于\(7\)。#......
  • Keyence Programming Contest 2020
    A-Painting每次取\(H,W\)中较大者涂就是了,输出\(\lceil\frac{n}{\max(H,W)}\rceil\)。代码:#include<iostream>#include<cstdio>usingnamespacestd;inth,w,n;intmain(){ scanf("%d%d%d",&h,&w,&n); if(h<w)swap(h,w); ......
  • NOMURA Programming Competition 2020
    A-StudyScheduling先算出总时间,然后在减去\(K\)就好了。代码:#include<iostream>#include<cstdio>usingnamespacestd;inth1,m1,h2,m2,k;intmain(){ scanf("%d%d%d%d%d",&h1,&m1,&h2,&m2,&k); intansh=h2-h1,ansm=m2-m1; if......
  • NIKKEI Programming Contest 2019-2
    A-SumofTwoIntegers分奇偶讨论一下就好了,答案为\(\lfloor\frac{n-1}\{2\}\rfloor\)。#include<iostream>#include<cstdio>usingnamespacestd;intn;intmain(){ scanf("%d",&n); printf("%d",(n-1)/2); return0;}B-......
  • Tenka1 Programmer Contest 2019
    C-Stones枚举分界点爆算即可。#include<iostream>#include<cstdio>usingnamespacestd;constintN=200005;intn;chars[N];intsum[N][2];intmain(){ scanf("%d",&n); scanf("%s",s+1); sum[0][0]=sum[0][1]=0; for(inti=1;i......
  • Social Infrastructure Information Systems Division, Hitachi Programming Contest
    A-HitachiString满足条件的串即为串长为偶数且相邻两个均为为hi,直接判断即可。代码:#include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;constintN=15;intn;chars[N];intmain(){ scanf("%s",s+1); n=strlen(s+1); if(n&1) ......