Codeforces Round #312 (Div. 2)

本文深入探讨AI音视频处理领域的关键技术,重点介绍视频分割与语义识别,通过实例解析如何利用AI技术实现高效的内容分析与理解。

A - Lala Land and Apple Trees 在一维直线上有一些苹果树,上面有一些苹果,从坐标处为0的点出发,向左或向右,每次遇到没摘的苹果树就摘光苹果然后掉头。问最多能摘多少苹果。

int n;
struct node{
	int a, p;
}v1[321], v2[321];

bool cmp( node q, node w )
{
	if( q.p > w.p )
		return 1;
	return 0;
}

int main()
{
	while( ~scanf("%d", &n) ) {
		int a, p, cnt1 = 0, cnt2 = 0;
		for( int i = 1; i <= n; ++i ) {
			scanf("%d%d", &p, &a);
			if( p < 0 )
				v1[cnt1].a = a, v1[cnt1++].p = p;
			else
				v2[cnt2].a = a, v2[cnt2++].p = p;
		}
		sort( v1, v1+cnt1, cmp );
		sort( v2, v2+cnt2, cmp );
		int m = min( cnt1, cnt2 );
		int ans = 0;
		for( int i = 0; i < m; ++i ) {
			ans += v1[i].a;
			ans += v2[cnt2-1-i].a;
		}
		if( cnt1 < cnt2 )
			ans += v2[cnt2-1-m].a;
		else if( cnt1 > cnt2 )
			ans += v1[m].a;
		printf("%d\n", ans);
	}
	return 0;
}

B - Amr and The Large Array给出一个数组,找出出现次数最多的那个数的左右两边,若长度相同则使长度尽量短

vector <int> v[N];

int main()
{
	int n, x;
	scanf("%d", &n);
	for( int i = 1; i <= n; ++i) {
		scanf("%d", &x);
		v[x].push_back(i);
	}
	int maxx = 0, l, r, len = inf;
	for( int i = 1; i <= 1000000; ++i ){
		if( v[i].size() > maxx ) {
			maxx = v[i].size();
			sort( v[i].begin(), v[i].end() );
			l = v[i][0], r = v[i][v[i].size()-1];
			len = r - l + 1;
		}
		else if( v[i].size() == maxx ) {
			if( maxx == 0 )
				continue;
			sort( v[i].begin(), v[i].end() );
			int ll = v[i][0], rr = v[i][v[i].size()-1];
			if( rr - ll + 1 < len ) {
				len = rr - ll + 1;
				l = ll;
				r = rr;
			}
		}
	}
	cout << l << " " << r << endl;
	return 0;
}
C - Amr and Chemistry 给出n种物品的数量,每次数量能*2 或/2,问使所有物品数量一样的最小操作数。

暴力枚举每种数量能达到的值及操作数,然后枚举并更新。注意若x能整除2那么x/2就不必向上扩展了

const int N = 100010;

queue <pair <int, int> > q;
int n;
int a[N];
pair<int, int> Hash[N];

int main()
{
    while( ~scanf("%d", &n) ) {
        for( int i = 1; i <= n; ++i ) {
            scanf("%d", &a[i]);
            Hash[i].first = Hash[i].second = 0;
        }
        for( int i = 1; i <= n; ++i ) {
            int x = a[i], cnt = 0;
            while( !q.empty() ) q.pop();
            q.push( Mp(x, cnt) );
            int sum = 0;
            while( x/2 >= 1 ) {
                cnt++;
                if( x & 1 ) {
                    q.push( Mp( x/2, cnt ) );
                }
                else {
                    Hash[x/2].first++;
                    Hash[x/2].second += cnt;
                }
                x /= 2;
            }
            while( !q.empty() ) {
                pair <int, int> t = q.front();
                q.pop();
                while( t.first < N ) {
                    Hash[t.first].first++;
                    Hash[t.first].second += t.second;
                    t.first <<= 1;
                    t.second++;
                }
            }
        }
        int ans = inf;
        for( int i = 1; i <= N; ++i ) {
            if( Hash[i].first < n )
                continue;
            //printf("%d\n", Hash[i].second);
            ans = min( ans, Hash[i].second );
        }
        printf("%d\n", ans);
    }
    return 0;
}
D - Guess Your Way Out! II 给出一颗完全二叉树,每次给出了 l, r, op,op = 1表示出口在【l,r】这颗子树包含的最下层叶子节点里面,或者op = 0表示出口不在【l,r】这颗子树的最下层叶子节点里。问最后是否最下层叶子节点是否有一个确定的出口。

每次将更新都表示在最下层叶子节点上面,将op=1的操作不断与之前的区间交最后得到一个确定的区间(若区间有多个那么就说明cheat),而将op=0的操作保存起来,最后与之前处理出来的区间进行更新,最后看确定的区间的数量和是否只有一个点,根据结果输出答案即可

const int N = 100010;

ll query, h;

struct node{
    ll l, r;
    bool operator < ( const node &rhs ) const {
        if( l == rhs.l )
            return r > rhs.r;
        return l < rhs.l;
    }
}a[N];
vector <node> v;

int main()
{
    while( ~scanf("%lld%lld", &h, &query) ) {
        v.clear();
        ll le, l, r, f, cnt = 0;
        bool cheat = 0;
        ll L = (1LL << (h - 1)), R = (1LL << h) - 1;
        while( query-- ) {
            scanf("%lld%lld%lld%lld", &le, &l, &r, &f);
            if( cheat )
                continue;
            l = l * (1LL<<(h-le));
            r = (r+1) * (1LL<<(h-le)) - 1;
            if( f ) {
                if( l > R || r < L ) {
                    cheat = 1;
                    continue;
                }
                else {
                    L = max( L, l );
                    R = min( R, r );
                }
            }
            else {
                node tmp;
                tmp.l = l, tmp.r = r;
                a[++cnt] = tmp;
            }
        }
        if( cheat ) {
            puts("Game cheated!");
            continue;
        }
        sort( a+1, a+cnt+1 );
        f = 1;
        for( int i = 1; i <= cnt; ++i ) {
			ll l = a[i].l, r = a[i].r;
			if( L > R ) {
				f = 0;
				break;
			}
			if( l > R )
				break;
			if( r < L )
				continue;
			if( l <= L && R <= r ) {
				f = 0;
				break;
			}
			if( L <= l && r <= R ) {
				node tmp;
				tmp.l = L, tmp.r = l-1;
				if( tmp.l <= tmp.r )
					v.push_back(tmp);
				L = r + 1;
				continue;
			}
			if( L <= l && R <= r ) {
				node tmp;
				tmp.l = L, tmp.r = l-1;
				if( tmp.l <= tmp.r )
					v.push_back(tmp);
				f = 0;
				break;
			}
			if( l <= L && r <= R )
				L = r+1;
		}
        if( L <= R && f ) {
            node tmp;
            tmp.l = L, tmp.r = R;
            v.push_back(tmp);
        }
        int sz = v.size();
        if( sz == 0 )
            puts("Game cheated!");
        else if( sz >= 2 || ( sz == 1 && v[0].r > v[0].l ) )
            puts("Data not sufficient!");
        else
            printf("%lld\n", v[0].l);
    }
    return 0;
}

E - A Simple Task 给出一个字符串,每次选出一段子区间,使得里面的字符升序或者降序重新排。操作完输出最后的结果。

开26颗线段树,每棵树保存对应从a~z的字符在某段区间的数量,每次操作的时候都相应的先删去那段操作区间的值,然后根据排的结果重新确定相应区间内该字符的数量。最后一次查询输出结果。

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <iomanip>
///cout << fixed << setprecision(13) << (double) x << endl;
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>

using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define ls rt << 1
#define rs rt << 1 | 1
#define pi acos(-1.0)
#define eps 1e-8
#define asd puts("sdfsdfsdfsdfsdfsdf");
#define Mp(a, b) make_pair(a, b)
typedef long long ll;
//typedef __int64 LL;
const int inf = 0x3f3f3f3f;
const int N = 100010;

struct node{
	int l, r;
	int add, x;
}tr[26][N << 2];
char a[N];
char ans[N];
int n, m;

void pushup( int id, int rt )
{
	tr[id][rt].x = tr[id][ls].x + tr[id][rs].x;
}

void down( int id, int rt )
{
	if( tr[id][rt].add ) {
		if( tr[id][rt].add == 1 ) {
			tr[id][ls].x = tr[id][ls].r - tr[id][ls].l + 1;
			tr[id][rs].x = tr[id][rs].r - tr[id][rs].l + 1;
		}
		else 
			tr[id][ls].x = tr[id][rs].x = 0;
		tr[id][ls].add = tr[id][rs].add = tr[id][rt].add;
		tr[id][rt].add = 0;
	}
}

void build( int id, int l, int r, int rt ) 
{
	tr[id][rt].l = l;
	tr[id][rt].r = r;
	tr[id][rt].add = 0;
	if( l == r ) {
		tr[id][rt].x = ( a[l] == 'a' + id );
		return;
	}
	int mid = ( l + r ) >> 1;
	build( id, lson );
	build( id, rson );
	pushup( id, rt );
}

int query( int id, int l, int r, int rt )
{
	if( l <= tr[id][rt].l && tr[id][rt].r <= r ) {
		return tr[id][rt].x;
	}
	down( id, rt );
	int mid = ( tr[id][rt].l + tr[id][rt].r ) >> 1;
	if( r <= mid )
		return query( id, l, r, ls );
	else if( l > mid )
		return query( id, l, r, rs );
	else
		return query( id, lson ) + query( id, rson );
}

void update( int id, int l, int r, int rt, int val )
{
	if( l <= tr[id][rt].l && tr[id][rt].r <= r ) {
		if( val == 1 )
			tr[id][rt].x = tr[id][rt].r - tr[id][rt].l + 1;
		else
			tr[id][rt].x = 0;
		tr[id][rt].add = val;
		return;
	}
	down( id, rt );
	int mid = ( tr[id][rt].l + tr[id][rt].r ) >> 1;
	if( r <= mid )
		update( id, l, r, ls, val );
	else if( l > mid )
		update( id, l, r, rs, val );
	else {
		update( id, lson, val );
		update( id, rson, val );
	}
	pushup( id, rt );
}

void get_ans( int id, int rt )
{
	if( tr[id][rt].l == tr[id][rt].r ) {
		if( tr[id][rt].x )
			ans[ tr[id][rt].l ] = id + 'a';
		return;
	}
	down( id, rt );
	get_ans( id, ls );
	get_ans( id, rs );
}

int main()
{
	while( ~scanf("%d%d", &n, &m) ) {
		scanf("%s", a+1);
		for( int i = 0; i < 26; ++i ) {
			build( i, 1, n, 1 );
		}
		for( int i = 1, l, r, op; i <= m; ++i ) {
			scanf("%d%d%d", &l, &r, &op);
			int tmp[30];
			for( int j = 0; j < 26; ++j ) {
				tmp[j] = query( j, l, r, 1 );
			}
			if( op == 1 ) {
				for( int j = 0; j < 26; ++j ) {
					update( j, l, r, 1, -1 );
				}
				int curl, curr, lastr = l-1;
				for( int j = 0; j < 26; ++j ) {
					if( !tmp[j] )
						continue;
					curl = lastr+1;
					curr = lastr + tmp[j];
					update( j, curl, curr, 1, 1 );
					//printf("char: %c l: %d r: %d\n", j+'a', curl, curr);
					lastr = curr;
				}
			}
			else {
				for( int j = 0; j < 26; ++j ) {
					update( j, l, r, 1, -1 );
				}
				int curl, curr, lastr = l-1;
				for( int j = 25; j >= 0; --j ) {
					if( !tmp[j] )
						continue;
					curl = lastr+1;
					curr = lastr+tmp[j];
					update( j, curl, curr, 1, 1 );
					//printf("char: %c l: %d r: %d\n", j+'a', curl, curr);
					lastr = curr;
				}
			}
		}
		ans[n+1] = '\n';
		for( int i = 0; i < 26; ++i ) {
			get_ans( i, 1 );
		}
		printf("%s\n", ans+1);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值