CodeForces_195B AfterTraining ( 模拟 | 规律 )

题目连接 -> cf and vj

题意

给n个球m个篮子, 要求按照以下顺序将球放到篮子里, 最后输出按照以下规则放到篮子里的球的篮子编号
*1 优先放入球数少的篮子里
*2 优先靠近中间的框
*3 两个中间位置优先输出编号小的框

题解

用模拟和找规律都可以做出来

找规律发现输出的其实就是按题意顺序的 m 个篮子编号的循环节, 那么我们可以将这个循环节打表存起来, 遍历 n 个球输出循环节即可, 需要注意一下循环节输出的取模技巧
比如 11 个球 和 3 个篮子
循环节数组

213
下标0123

1 % 3 = 1 -----------------------------------------------------------------> 2
2 % 3 = 2 -----------------------------------------------------------------> 1
3 % 3 = 0 -> 此时令赋值为 3, 指向下标为 3 的位置-----------------------> 3
4 % 3 = 1 -----------------------------------------------------------------> 2
5 % 3 = 2 -----------------------------------------------------------------> 1
6 % 3 = 0 -> 此时令赋值为 3, 指向下标为 3 的位置-----------------------> 3
7 % 3 = 1 -----------------------------------------------------------------> 2
8 % 3 = 2 -----------------------------------------------------------------> 1
9 % 3 = 0 -> 此时令赋值为 3, 指向下标为 3 的位置-----------------------> 3
10 % 3 = 1 ---------------------------------------------------------------> 2
11 % 3 = 2 ---------------------------------------------------------------> 1

单纯的模拟用一个结构体封装每个球所在篮子的三个属性并做好初始化: 存球数量, 此篮子离中间篮子的距离( 当然需讨论奇数和偶数个篮子时 到中间位置的情况 ), 篮子编号. 然后模拟每次将一个球放到篮子里的过程, 找一个篮子, 球放进去( 篮子里的球数自增 ), 同时输出篮子编号

代码

规律大法 … 找规律找到循环节, 输出一串数一节

在这里插入图片描述

#include <bits/stdc++.h> 
using namespace std; 
#define rg register 
#define sc scanf 
#define pf printf 
typedef long long ll; 

// const int MAXN = 1e2+10;
const int MAXN = 1e5+10;

int main ( ) {  // freopen( "F:\\in\\.txt" , "r" , stdin ); 

	int n, m;
	sc( "%d%d", &n, &m );

	int mid1, mid2;
	int ans[MAXN];
	bool flag = true; 

	if ( m%2 ) { // 奇数个篮筐求中间位置
		mid1 = mid2 = (m+1)/2;
		ans[1] = mid1;
// cout << ans[1] << " ";
		mid1--, mid2++;
		for ( int i = 2; i <= m; ++i ) {
			if ( flag ) { 
				ans[i] = mid1--;
// cout << ans[i] << " ";
				flag = false;
			} else {
				ans[i] = mid2++;
// cout << ans[i] << " ";
				flag = true;
			}
		}
	}
	else { // 偶数个
		mid1 = m/2;
		mid2 = mid1+1;
		for ( int i = 1; i <= m; ++i ) {
			if ( flag ) { 
				ans[i] = mid1--;
				flag = false;
// cout << ans[i] << " ";
			} else {
				ans[i] = mid2++;
				flag = true;
// cout << ans[i] << " ";	
			}
		}
	}
// cout << endl;




	for ( int i = 1; i <= n; ++i ) 
		pf ( "%d\n", ans[i%m!=0 ? i%m : m] );	









	return 0 ; 
} 

模拟大法, 按题意重载小于号, 每次取出头模拟

可惜是c++学的不精, 不太明白重载友元函数和直接重载小于号的区别, 上面的是普通重载, 下面结尾处注释的是友元函数重载小于号, 不懂, 只知道普通重载慢了 … 这算是不求甚解?
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
#define rg register
#define sc scanf
#define pf printf
const int MAXN = 1e5*3;

struct NODE {
	int cnt, dis, id;
	NODE ( ) { };
	NODE ( int cnt, int dis, int id ) : cnt(cnt), dis(dis), id(id) { };
	inline bool operator < ( const NODE& t ) const { 
		if ( cnt < t.cnt ) return true;
		else if ( cnt == t.cnt ) {
			if ( dis < t.dis ) return true;
			else if ( dis == t.dis ) {
				if ( id < t.id ) return true;
				else 			return false;
			} else return false;
		} else return false;
	}
};

int main ( ) {

    int n, m;
	set<NODE>s;

	while ( ~sc ( "%d%d", &n, &m ) ) {

		s.clear ( );

		int mid1, mid2;
		if ( m%2 ) { // 奇数个篮筐求中间位置
			mid1 = mid2 = (m+1)/2;
		}
		else { // 偶数个
			mid1 = m/2;
			mid2 = mid1+1;
		}

		for ( int i = 1; i <= m; ++i ) { // 初始化每个篮筐
			s.insert ( NODE( 0, min(abs(mid1-i), abs(mid2-i)), i ) );
		}

		for ( int i = 1; i <= n; ++i ) {
			NODE tx = *s.begin ( );
			s.erase ( s.begin ( ) );
			tx.cnt++;
			s.insert ( tx );
			pf ( "%d\n", tx.id );
		}









	}


	return 0;
}
// inline friend bool operator < ( const NODE &x, const NODE &y ) {
	// 	if ( x.cnt < y.cnt )return true;
	// 	else if ( x.cnt == y.cnt ) {
	// 		if ( x.dis < y.dis )return true;
	// 		else if ( x.dis == y.dis ) {
	// 			if ( x.id < y.id )return true;
	// 			else return false;
	// 		}
	// 		else return false;
	// 	}
	// 	else return false;
	// }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值