2024牛客暑期多校训练营10——L Tada!

原题
题目链接:登录—专业IT笔试面试备考平台_牛客网牛客网是互联网求职神器,C++、Java、前端、产品、运营技能学习/备考/求职题库,在线进行百度阿里腾讯网易等互联网名企笔试面试模拟考试练习,和牛人一起讨论经典试题,全面提升你的技术能力icon-default.png?t=N7T8https://ac.nowcoder.com/acm/contest/81605/L
来源:牛客网

There is a combination lock with n (1≤n≤5)n~ (1 \leq n \leq 5)n (1≤n≤5) digits , each digit being between 0∼90 \sim 90∼9. For each digit, turning it clockwise by one position will change the digit from xxx to x+1 mod 10x + 1 \bmod 10x+1mod10. For example, 000 becomes 111, 111 becomes 222, and 999 turns into 000. Turning it counterclockwise does the opposite, changing the digit to x+9 mod 10x + 9 \bmod 10x+9mod10.

Little Cyan Fish has locked the secrets of the China Clattering Processing Contest (CCPC) with this combination lock. Every day, to secure the secrets, Little Cyan Fish scrambles the combination by repeating the following operations for some number of times: turning an interval [l,r] (1≤l≤r≤n)[l, r]~(1 \leq l \leq r \leq n)[l,r] (1≤l≤r≤n) of digits by one position, each turn accompanied by a distinct ``tada'' sound.

As Big Black Fish, who is secretly positioned next to Little Cyan Fish, you aim to steal the secrets for a reward. You eavesdrop on Little Cyan Fish's locking process daily, recording the number of ``tada'' sounds --- which is the number of operations, and then inspect the digits on the lock in the dead of night.

You have collected mmm pieces of information, and you need to determine whether the information collected uniquely identifies the correct combination.

题目大意

一个 n 位 0 ∼ 9 的转轮密码锁,拨动方式是每次选择一个区间,顺时针 或者逆时针转动一位。 从某个特定的密码出发,给定 m 条转动了 t 次到达了状态 s 的记录,问 密码是否有解,如果有唯一解输出唯一解。 n ≤ 5, m ≤ 50, ∑10n ≤ 3 × 105 .

题目思路

从 00000 出发, 我们可以知道到每个状态需要几步(下图数组a)。 由于操作可逆(x, y(逆)),将每次的终态 s 看做 00000, 我们可以知道哪些位置能 在 t 步内到达 s: 首先最短路一定不能超过 t; 如果 x 步能到,x + 2 步一定能到,因为可以来回旋转相同的格子来浪费 时间。注意 x + 1 不一定能到——(所以最后判断分奇偶):

例如 t = 1 时最短路为 0 的情况,以及 n = 1 的情况。 因此距离的奇偶分开维护,对 m 个大小至多为 10n 的集合求交即可。 最短路复杂度 O(10nn 2 ), 集合求交复杂度 O(10nm).

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl '\n'
#define PII pair<int, int>
#define pb push_back
#define F first
#define S second
const int N = 2e6 + 10, mod = 998244353, M = 1e3 + 10, MAX = 1e18;
int n, m, k, t[M], a[M], ans;
map<int, int> vis;
string s[M];

int mi(int a, int b){  //快速幂 
	int res = 1;
	while(b){
		if(b & 1) res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}

void solve(){
	cin >> n >> m;
	for(int i = 1; i <= m; i ++){
		cin >> s[i] >> t[i];
	}
	for(int p = 0; p < mi(10, n); p ++){  //n位大小的数 
		int l = p;
		for(int i = 1; i <= n; i ++){
			a[n - i] = l % 10;
			l /= 10;
		}
		//上述a数组表示为 n位数字p的值,不足用0补 (如图 1所示) 
//		for(int i = 0; i < n; i ++){   
//			cout << a[i];
//		}
//		cout << ' ' << p << endl;
		int cnt = 0;
		for(int i = 1; i <= m; i ++){  
			int f = 0;
			int x = 0, y = 0, lx = 0, ly = 0; //lx, ly 为上次情况, 以下rx, ry为当前情况 x, y为最终值 
			for(int j = 0; j < n; j ++){
				int rx = (s[i][j] - '0' + 10 - a[j]) % 10; //取每种情况的每一位和当前处理的数组那位 %10 取出当前位 
				int ry = (10 - rx) % 10; //与rx的互补位 
				int px = x;  //当前x的值预留下来,中途 x会变 
				if(rx > lx) x = min(x + rx - lx, y + rx); //rx - lx 差值 
				else x = min(x, y + rx);
				if(ry > ly) y = min(y + ry - ly, px + ry); 
				else y = min(y, px + ry);
				lx = rx; //本次用好, 赋值给上次 
				ly = ry;
			}
			x = min(x, y);  //x, y为2种转的情况, 选择小值 
			if((n != 1 || (x + 100 - t[i]) % 2 == 0) && (x || t[i] != 1) && x <= t[i]) f = 1;//同倍数情况可以去(分奇偶) 
			if(f) cnt ++; //满足情况个数 
		}
		if(cnt == m) vis[p] = 1;
	}
	if(vis.size() > 1) cout << "MANY" << endl;
	else if(vis.size()){
		int p = vis.begin()->F; //vis.size() == 1 当前F就是我们值 
//		cout << p << endl;   //不能这样(可能有前导零) 
		for(int i = n; i >= 1; i --){ //每位取出 
			cout << p / mi(10, i - 1) % 10;
		}
		cout << endl;
	}
	else cout << "IMPOSSIBLE" << endl;
	vis.clear();
	return ;
}

signed main(){
	IOS
	int T = 1;
	cin >> T;
	while(T --) solve();
	return 0;
}

a数组下图所示:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值