“玲珑杯”算法比赛 Round #14题目与标程


         “玲珑杯”算法比赛 Round #14By:wxh010910

  Start Time:2017-05-13 16:00:00 End Time:2017-05-13 18:30:00 Refresh Time:2017-05-20 09:51:24 Public

             玲珑OJ比赛提交地址:http://www.ifrog.cc/acm/contest/1016

                       Round#14题解:http://www.ifrog.cc/acm/solution/19

A -- No Game No Life

Time Limit:1s Memory Limit:256MByte

Submissions:473Solved:226

DESCRIPTION

一对叫做 的兄妹玩游戏特别厉害,组队吊打所有人,

但是现实世界对他们很不友好,所以他们就去了异世界,

那个异世界有16个种族,不能打仗,只能玩游戏。

有一次他们和数据结构种族的人比赛,看谁写数据结构写得快,这时候出现了这样一道题:

给一个序列a,每次两个操作。

1、把所有数字x变成y2、询问序列一个位置上面的值

INPUT
第一行两个数n,m第二行n个数表示a序列后面有m行,
每行格式为1 x y或者2 x分别表示把所有值为x的数变成y或者询问序列上x位置的数值
OUTPUT
对于每个2操作,即询问,输出一个数表示答案
SAMPLE INPUT
5 55 5 5 5 52 31 5 22 31 8 32 1
SAMPLE OUTPUT
522
HINT
n,m <= 1000, a[i] <= 1000000000你作为妹妹当然要AC掉这题啦

标程:

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

int n , m , a[ MAXN ];
map < int , int > wocaonimalegebia;

inline int read()
{
	register int x = 0 , ch = getchar();
	while( !isdigit( ch ) ) ch = getchar();
	while( isdigit( ch ) ) x = x * 10 + ch - '0' , ch = getchar();
	return x;
}

int main()
{
	n = read() , m = read();
	for( register int i = 1 ; i <= n ; i++ ) a[i] = read() , wocaonimalegebia[ a[i] ] = a[i];
	while( m-- )
		if( read() == 1 )
		{
			int x = read();
			wocaonimalegebia[x] = read();
		}
		else printf( "%d\n" , wocaonimalegebia[ a[ read() ] ] );
	return 0;
}

B -- RE:从零开始的异世界生活

Time Limit:1s Memory Limit:256MByte

Submissions:368Solved:52

DESCRIPTION

486到了异世界,看到了一群可爱的妹子比如蕾姆啊,艾米莉亚啊,拉姆啊,白鲸啊,怠惰啊等等!
有一天膜女告诉486说她的能力可能不能再用了,因为膜女在思考一个数据结构题,没心情管486了。
486说我来帮你做,膜女说你很棒棒哦!

给一个集合,最开始为空(不是数学上的集合)
五个操作:

1、插入x
2、把小于x的数变成x
3、把大于x的数变成x
4、求集合中第x小数
5、求集合中小于x的数个数

INPUT
第一行一个数m后面有m行,每行格式为opt x,opt表示是什么操作,x表示操作的值
OUTPUT
对于每个4,5操作,输出一个值表示答案
SAMPLE INPUT
51 11 34 12 334 1
SAMPLE OUTPUT
133
HINT
m <= 100000 , x <= 1000000000
    标程:

#include <bits/stdc++.h>
#define ratio 4
#define MAXN 1000010
#define merge( a , b ) new_Node( a -> size + b -> size , b -> value , a , b )
#define new_Node( s , v , a , b ) ( & ( * st[ cnt++ ] = Node( s , v , a , b ) ) )
#define update( cur ) if( cur -> left -> size ) cur -> size = cur -> left -> size + cur -> right -> size , cur -> value = cur -> right -> value;

using namespace std;

struct Node
{
	int size , value;
	Node * left , * right;
	Node( int s , int v , Node * a , Node * b ) : size( s ) , value( v ) , left( a ) , right( b ) {}
	Node() {}
} * root , * null , * st[300000] , t[300000];

int n , m , x , cnt;

int find( int x , Node * cur )
{
	if( !cur -> left -> size ) return cur -> value;
	return x > cur -> left -> size ? find( x - cur -> left -> size , cur -> right ) : find( x , cur -> left );
}

int zhentamashabibuyaoxiajibaqibianlaingminghaobuhaoa( int x , Node * cur )
{
	if( !cur -> left -> size ) return ( x > cur -> value ) * cur -> size;
	return x > cur -> left -> value ? zhentamashabibuyaoxiajibaqibianlaingminghaobuhaoa( x , cur -> right ) + cur -> left -> size : zhentamashabibuyaoxiajibaqibianlaingminghaobuhaoa( x , cur -> left );
}

void split( int x , Node * cur )
{
	if( x > cur -> left -> size ) split( x - cur -> left -> size , cur -> right ) , cur -> left = merge( cur -> left , cur -> right -> left ) , st[ --cnt ] = cur -> right , cur -> right = cur -> right -> right;
	else if( x < cur -> left -> size ) split( x , cur -> left ) , cur -> right = merge( cur -> left -> right , cur -> right ) , st[ --cnt ] = cur -> left , cur -> left = cur -> left -> left;
}

void insert( int x , Node * cur )
{
	if( !cur -> left -> size )
		if( cur -> value < x ) cur -> left = new_Node( cur -> size , cur -> value , null , null ) , cur -> right = new_Node( 1 , x , null , null );
		else cur -> left = new_Node( 1 , x , null , null ) , cur -> right = new_Node( cur -> size , cur -> value , null , null );
	else insert( x , x > cur -> left -> value ? cur -> right : cur -> left );
	update( cur );
}

void dispose( Node * cur )
{
	if( cur -> left -> size ) st[ --cnt ] = cur -> left , st[ --cnt ] = cur -> right , dispose( cur -> left ) , dispose( cur -> right );
}

inline void low( int x )
{
	Node * cur = root;
	int s = zhentamashabibuyaoxiajibaqibianlaingminghaobuhaoa( x + 1 , cur );
	if( s == 0 );
	else if( s == cur -> size )
		dispose( cur ) , * cur = Node( s , x , null , null );
	else
		split( s , cur ) , dispose( cur -> left ) , * cur -> left = Node( s , x , null , null );
}

inline void up( int x )
{
	Node * cur = root;
	int s = zhentamashabibuyaoxiajibaqibianlaingminghaobuhaoa( x + 1 , cur );
	if( s == 0 )
		dispose( cur ) , * cur = Node( cur -> size , x , null , null );
	else if( s == cur -> size );
	else
		split( s , cur ) , dispose( cur -> right ) , * cur -> right = Node( cur -> size - s , x , null , null );
}

struct io
{
	char ibuf[1 << 23] , * s , obuf[1 << 22] , * t;
	int a[24];
	io() : t( obuf )
	{
		fread( s = ibuf , 1 , 1 << 23 , stdin );
	}
	~io()
	{
		fwrite( obuf , 1 , t - obuf , stdout );
	}
	inline int read() 
	{
		register int u = 0;
		while( * s < 48 ) s++;
		while( * s > 32 )
			u = u * 10 + * s++ - 48;
		return u;
	}
	template< class T >
	inline void print( register T u )
	{
		static int * q = a;
		if( !u ) * t++ = 48;
		else
		{
			if( u < 0 )
				* t++ = 45 , u *= -1;
			while( u ) * q++ = u % 10 + 48 , u /= 10;
			while( q != a )
				* t++ = * --q;
		}
		* t++ = '\n';
	}
} ip;

#define read ip.read
#define print ip.print

int main()
{
	m = read();
	for( register int i = 0 ; i < 300000 ; i++ ) st[i] = & t[i];
	null = new_Node( 0 , 0 , 0 , 0 );
	while( m-- )
	{
		int opt = read();
		if( opt == 1 )
			if( root ) insert( read() , root );
			else root = new_Node( 1 , read() , null , null );
		else if( opt == 2 ) low( read() );
		else if( opt == 3 ) up( read() );
		else if( opt == 4 ) print( find( read() , root ) );
		else print( zhentamashabibuyaoxiajibaqibianlaingminghaobuhaoa( read() , root ) );
	}
	return 0;
}

C -- Another

Time Limit:3s Memory Limit:256MByte

Submissions:230Solved:20

DESCRIPTION

因为奇怪的原因,主角榊原恒一转学到了夜见山市,进入了3年3班,看到了一个非常可爱的妹子Misaki。
但是…为什么其他同学都看不见Misaki呢?为什么Misaki被叫做不存在的人呢?为什么班上一直在死人呢?
为了搞清楚这件事情,主角去学习了OI,准备用图灵测试看看妹子是不是AI(正常人不应该怀疑妹子是不是鬼吗)
在NOIP day1T2,他遇到了一道数据结构题:

给你一个树,每个点有一个颜色,每种颜色有一个值t,定义一个点的跑步程度ans为:
设子树中颜色为x的点有y个,如果y >= t[x] , ans++;
求所有点的跑步程度的和

INPUT
第一行两个数n,h,h表示颜色个数后面有n - 1行,每行一个数表示该点的父亲后面有n行,表示每个点的颜色后面有h行,每行表示该颜色的t
OUTPUT
输出一个值表示答案
SAMPLE INPUT
5 512341 2 3 4 511111
SAMPLE OUTPUT
15
HINT
n,m,h,t <= 100000若出现爆栈问题,改栈方法请参考1093题目代码1093地址:http://www.ifrog.cc/acm/problem/1093代码地址:http://ideone.com/Wk24ET

               标程:

                     

#define OPENSTACK
#include <bits/stdc++.h>
using namespace std;
#define MAXN 500010

using namespace std;

int n , h , size[ MAXN ] , fa[ MAXN ] , dep[ MAXN ] , son[ MAXN ] , top[ MAXN ] , l[ MAXN ] , r[ MAXN ] , tag[ MAXN ] , tot , p[10000000] , cnt;
vector < int > linker[ MAXN ] , wocaonimabi[ MAXN ];
long long ans;

inline int read()
{
	int x = 0 , ch = getchar();
	while( !isdigit( ch ) ) ch = getchar();
	while( isdigit( ch ) ) x = x * 10 + ch - '0' , ch = getchar();
	return x;
}

#define cur linker[x][i]

void dfs1( int x )
{
	size[x] = 1;
	for( int i = 0 ; i < linker[x].size() ; i++ )
		if( cur != fa[x] )
		{
			fa[ cur ] = x , dep[ cur ] = dep[x] + 1;
			dfs1( cur ) , size[x] += size[ cur ];
			if( size[ cur ] > size[ son[x] ] ) son[x] = cur;
		}
}

void dfs2(int x, int t) {
	top[x] = t;
	l[x] = ++tot;
	if (son[x] ) {
		dfs2( son[x] , t );
	}
	for( int i = 0 ; i < linker[x].size() ; i++ )
		if( cur != fa[x] && cur != son[x] )
			dfs2( cur , cur );
}

inline void modify( int l , int r )
{
	tag[l]++ , tag[r + 1]--;
	p[ ++cnt ] = l , p[ ++cnt ] = r + 1;
}

void modify( int x )
{
	while( x )
	{
		modify( l[ top[x] ] , l[x] );
		x = fa[ top[x] ];
	}
}

inline void addedge(int x, int y) {
	linker[x].push_back( y );
}

int main()
{
	#ifdef OPENSTACK
		int size = 128 << 20; // 64MB
		char *tangtangtangtanglaoshia = (char*)malloc(size) + size;
		#if (defined _WIN64) or (defined __unix)
			__asm__("movq %0, %%rsp\n" :: "r"(tangtangtangtanglaoshia));
		#else
			__asm__("movl %0, %%esp\n" :: "r"(tangtangtangtanglaoshia));
		#endif
	#endif
	n = read() , h = read();
	for( int i = 2 ; i <= n ; i++ ) addedge( read() , i );
	for( int i = 1 ; i <= n ; i++ ) wocaonimabi[ read() ].push_back( i );
	dfs1( 1 );
	dfs2( 1 , 1 );
	for( int v = 1 ; v <= h ; v++ )
	{
		int t = read();
		for(int i = 0 ; i < wocaonimabi[v].size() ; i++ )
			modify( wocaonimabi[v][i] );
		p[ ++cnt ] = 1 , p[ ++cnt ] = n + 1;
		sort( p + 1 , p + cnt + 1 );
		cnt = unique( p + 1 , p + cnt + 1 ) - p;
		for(int i = 1 , last = 1 , now = 0 ; i <= cnt ; i++ )
		{
			if( now >= t ) ans += p[i] - last;
			now += tag[ p[i] ] , tag[ p[i] ] = 0;
			last = p[i];
		}
		cnt = 0;
	}
	cout << ans << endl;
	#ifdef OPENSTACK
		exit(0);
	#else
		return 0;
	#endif
}

D -- 轻拍翻转小膜女

Time Limit:1s Memory Limit:256MByte

Submissions:36Solved:4

DESCRIPTION

可可娜是一个可爱的初中二年级妹子,本来在认真学习的她偶遇了膜法少女帕比卡,于是和她一起潜入称为pure illusion的异世界,寻找“mimi的碎片”,据说找齐了所有碎片可以掌控pure illusion从而掌控世界。
但是…
这番其实讲的是家庭伦理…
先不管这么多,有一次可可娜和帕比卡进入了一个神奇的异世界,里面全部是数据结构题。
她们终于做出了所有题,拿到了碎片,正准备离开,突然发现离开的出口上还有最后一道题没被AC,这个题是这样的:

一个序列a,一个操作:
每次询问一个区间,是否存在两个不同数x,y,使得x = y * z,这里指的是整除!

INPUT
第一行两个数n,m第二行n个数表示a序列后面有m行,每行为l r z表示一个操作
OUTPUT
对于每个操作,输出”flip”表示可以,输出“flap”表示不可以
SAMPLE INPUT
5 51 2 4 8 161 2 22 4 44 5 21 2 82 4 5
SAMPLE OUTPUT
flipflipflipflapflap
HINT
n,m,a[i] <= 1000002 <= z <= 100000

  标程:

       

#include<bits/stdc++.h>
#define MAXN 100010
 
using namespace std;
 
int n , m , block , a[ MAXN ], belong[ MAXN ] , ans[ MAXN ] , cnt[ MAXN ] , last[ MAXN ];
 
struct ask
{
        int v , l , r , pos;
} q[ MAXN ];
 
vector < ask > linker[MAXN ];
 
inline bool cmp( const ask& a , const ask & b )
{
        return belong[ a.l ] ^ belong[ b.l ] ? belong[ a.l ] <belong[ b.l ] : belong[ a.l ] & 1 ? a.r < b.r : a.r > b.r;
}
 
inline int read()
{
        register int x = 0 , ch = getchar();
        while( !isdigit( ch ) ) ch = getchar();
        while( isdigit( ch ) ) x = x * 10 + ch - '0' , ch =getchar();
        return x;
}
 
int main()
{
        n = read() , m = read();
        block = n / sqrt( m / 3 );
        for( register int i = 1 ; i <= n ; i++ ) belong[i] = ( i -1 ) / block , a[i] = read();
        for( register int i = 1 ; i <= m ; i++ )
               q[i].l = read() , q[i].r = read() , q[i].v = read() ,q[i].pos = i;
        sort( q + 1 , q + m + 1 , cmp );
        for( int i = 1 , l = 1 , r = 0 ; i <= m ; i++ )
        {
               while( l > q[i].l ) cnt[ a[ --l ] ]++;
               while( r < q[i].r ) cnt[ a[ ++r ] ]++;
               while( l < q[i].l ) cnt[ a[ l++ ] ]--;
               while( r > q[i].r ) cnt[ a[ r-- ] ]--;
               if( q[i].v > 300 )
                       for( register int j = 1 ; j * q[i].v <=100000 && !ans[ q[i].pos ] ; j++ )
                               if( cnt[j] && cnt[ j * q[i].v] )
                                      ans[ q[i].pos ] = 1;
        }
        for( int x = 1 ; x <= 300 ; x++ )
        {
                for( registerint i = 1 ; i <= n ; i++ ) linker[i].clear();
               for( register int i = 1 ; i <= m ; i++ )
                       if( q[i].v == x )
                               linker[ q[i].l ].push_back( q[i] );
               memset( last , 0x3f , sizeof( last ) );
               for( register int i = n , j = n + 1 ; i ; i-- )
               {
                       if( a[i] * 1ll * x <= 100000 ) j = min( j ,last[ a[i] * 1ll * x ] );
                       if( a[i] % x == 0 ) j = min( j , last[ a[i] /x ] );
                       for( register int k = 0 ; k <linker[i].size() ; k++ )
                               if( linker[i][k].r >= j )
                                      ans[ linker[i][k].pos ] = 1;
                       last[ a[i] ] = i;
               }
        }
        for( register int i = 1 ; i <= m ; i++ )
               puts( ans[i] ? "flip" : "flap" );
        return 0;
}       

E -- 大头日

Time Limit:2s Memory Limit:256MByte

Submissions:69Solved:3

DESCRIPTION


怼大佬是会掉人品的,如果怼成功了,那么rp--,否则rp不变。
有n个大佬,任意两个大佬之间都互相怼了一次,他们之间必有一个怼对方成功,而另一个失败。
具体来说,这形成了一个竞赛图,即任意两点之间有且仅有一条有向边。
每个大佬的初始rp都是0,他们互相怼之后把所有人的rp排序,问有多少种本质不同的rp序列?

INPUT
一行一个整数表示n。
OUTPUT
一行一个整数表示答案模998244353的值。
SAMPLE INPUT
1
SAMPLE OUTPUT
1
HINT
n <= 100000

   标程:

        

#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define fill( x, y ) memset( x, y, sizeof x )
#define copy( x, y ) memcpy( x, y, sizeof x ) 
using namespace std;

typedef long long LL;
typedef pair < int, int > pa;

inline int read()
{
	int sc = 0, f = 1; char ch = getchar();
	while( ch < '0' || ch > '9' ) { if( ch == '-' ) f = -1; ch = getchar(); }
	while( ch >= '0' && ch <= '9' ) sc = sc * 10 + ch - '0', ch = getchar();
	return sc * f;
}

const int mod = 998244353;
const int MAXN = 262145;

inline int qpow(int x, int y, int mod) { int ret = 1; for( ; y ; y >>= 1, x = 1LL * x * x % mod ) if( y & 1 ) ret = 1LL * ret * x % mod; return ret; }

namespace NTT
{
	int R[MAXN], n, L, inv;

	inline void getR() { for( int i = 0 ; i < n ; i++ ) R[ i ] = ( R[ i >> 1 ] >> 1 ) | ( ( i & 1 ) << L - 1 ); inv = qpow( n, mod - 2, mod ); }

	inline void NTT(int *a, int f)
	{
		for( int i = 0 ; i < n ; i++ ) if( i < R[ i ] ) swap( a[ i ], a[ R[ i ] ] );
		for( int i = 1, wn = qpow( 3, mod - 1 + f * ( mod - 1 ) / ( i << 1 ), mod ) ; i < n ; i <<= 1, wn = qpow( 3, mod - 1 + f * ( mod - 1 ) / ( i << 1 ), mod ) )
			for( int j = 0, w = 1; j < n ; j += i << 1, w = 1 )
				for( int k = 0 ; k < i ; k++, w = 1LL * w * wn % mod )
				{
					int x = a[ j + k ], y = 1LL * w * a[ j + k + i ] % mod;
					a[ j + k ] = ( x + y ) % mod; a[ j + k + i ] = ( x - y + mod ) % mod;
				}
		if( f < 0 ) for( int i = 0 ; i < n ; i++ ) a[ i ] = 1LL * a[ i ] * inv % mod;
	}

	inline void mul(int *ret, int *a, int *b)
	{
		NTT( a, 1 ); NTT( b, 1 );
		for( int i = 0 ; i < n ; i++ ) ret[ i ] = 1LL * a[ i ] * b[ i ] % mod;
		NTT( ret, -1 );
	}
}

inline void inc(int &x, int y) { x += y; if( x >= mod ) x -= mod; }
inline void dec(int &x, int y) { x -= y; if( x < 0 ) x += mod; }

int n, f[MAXN], g[MAXN], fac[MAXN], inv[MAXN], fnv[MAXN], p[MAXN], p_cnt, phi[MAXN], a[MAXN], b[MAXN], c[MAXN];

inline int C(int x, int y) { return 1LL * fac[ x ] * fnv[ y ] % mod * fnv[ x - y ] % mod; }

inline void init()
{
	fac[ 0 ] = inv[ 0 ] = inv[ 1 ] = fnv[ 0 ] = phi[ 1 ] = f[ 0 ] = 1;
	for( int i = 1 ; i <= ( n << 1 ) ; i++ ) fac[ i ] = 1LL * fac[ i - 1 ] * i % mod;
   	for( int i = 2 ; i <= ( n << 1 ) ; i++ ) inv[ i ] = 1LL * ( mod - mod / i ) * inv[ mod % i ] % mod;
   	for( int i = 1 ; i <= ( n << 1 ) ; i++ ) fnv[ i ] = 1LL * fnv[ i - 1 ] * inv[ i ] % mod;
	for( int i = 2 ; i <= n ; i++ )
	{
		if( !phi[ i ] ) phi[ p[ ++p_cnt ] = i ] = i - 1;
		for( int j = 1 ; i * p[ j ] <= n ; j++ )
		{
			if( i % p[ j ] == 0 )
			{
				phi[ i * p[ j ] ] = phi[ i ] * p[ j ];
				break;
			}
			phi[ i * p[ j ] ] = phi[ i ] * ( p[ j ] - 1 );
		}
	}
	for( int i = 1 ; i <= n ; i++ )
	{
		int t = C( i << 1, i );
		for( int j = i, k = 1 ; j <= n ; j += i, k++ )
			if( i & 1 ) dec( g[ j ], 1LL * phi[ k ] * t % mod );
			else inc( g[ j ], 1LL * phi[ k ] * t % mod );
		if( i & 1 ) g[ i ] = ( mod - g[ i ] ) % mod;
		g[ i ] = 1LL * g[ i ] * inv[ i << 1 ] % mod;
	}
}

inline void solve(int l, int r)
{
	if( l == r ) { f[ l ] = 1LL * f[ l ] * inv[ l ] % mod; return ; }
	int mid = l + r >> 1;
	solve( l, mid );
	for( NTT::n = 1, NTT::L = 0 ; NTT::n <= r - l + 1 ; NTT::n <<= 1 ) NTT::L++;
	NTT::getR();
	for( int i = 0 ; i < NTT::n ; i++ )
		a[ i ] = i + l <= mid ? f[ i + l ] : 0, b[ i ] = ( i + l + 1 ) <= r ? g[ i + 1 ] : 0;
	NTT::mul( c, a, b );
	for( int i = mid + 1 ; i <= r ; i++ )
		inc( f[ i ], c[ i - l - 1 ] );
	solve( mid + 1, r );
}

int main()
{
	n = read();
	init();
	solve( 0, n );
	return printf( "%d\n", f[ n ] ), 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值