2020 ICPC Universidad Nacional de Colombia Programming Contest

题目ABCDEFGHIJKLMN
Solved ∙ \bullet ∙ \bullet ∙ \bullet ♠ \spadesuit ∙ \bullet ♠ \spadesuit ♠ \spadesuit ∙ \bullet ♠ \spadesuit

♠ \spadesuit 比赛时通过; ∙ \bullet :赛后通过; ⊘ \oslash :比赛时尝试了未通过; ∘ \circ :比赛时未尝试

A.Approach

这题有个坑点,首先三分算法肯定是想得到的了,主要是当一个点走完以后,另一个点在走的过程中可能还会出现小的抛物线,所以需要分两种情况讨论,详情见代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pll;
template <typename T>
inline void rd(T& x)
{
	ll tmp = 1; char c = getchar(); x = 0;
	while (c > '9' || c < '0') { if (c == '-')tmp = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	x *= tmp;
}
const ll inf = 0x3f3f3f3f;
const ll mod = 1e9+7;
const ll N = 2e3 + 10;
const ll M=1e7+10;
const double eps=1e-8;
struct Point{
	double x,y;
	Point(){}
	Point(double x, double y):x(x),y(y){}
	Point operator+(const Point &B){ return Point(x+B.x,y+B.y);}
	Point operator-(const Point &B){ return Point(x-B.x,y-B.y);}
	Point operator*(double k){ return Point(x*k,y*k);}
	void input(){
		cin>>x>>y;
	}
}st1,ed1,st2,ed2;
struct Line{
	Point st,ed;
	double len,ang;
	void input(){
		st.input();ed.input();
		ang=atan2(ed.y-st.y,ed.x-st.x);
	}
}a,b;
double Distance(Point A,Point B){
	double ans=(A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);
	return sqrt(ans);
}
double get_dis(double mid){
	Point p1=Point(a.st.x+min(mid,a.len)*cos(a.ang),a.st.y+min(mid,a.len)*sin(a.ang));
	Point p2=Point(b.st.x+min(mid,b.len)*cos(b.ang),b.st.y+min(mid,b.len)*sin(b.ang));
	double ans=Distance(p1,p2);
	return ans;
}
double solve(double l,double r){
	for(int i=1;i<=1e2;++i){
		double midl=(l*2+r)/3,midr=(l+r*2)/3;
		if(get_dis(l)<get_dis(r)){
			r=midr;
		}
		else{
			l=midl;
		}
	}
	double ans=get_dis(l);
	if(ans-get_dis(r)>eps){
        ans=get_dis(r);
	}
	return ans;
}
int main() { 
	ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
	a.input();b.input(); 
	double l=0,r=max(a.len=Distance(a.st,a.ed),b.len=Distance(b.st,b.ed));
	printf("%.12lf\n",min(solve(0,min(a.len,b.len)),solve(min(a.len,b.len),max(a.len,b.len))));
	return 0;
}

B.Baby name

一道思维题,赛内没通过可惜到裂开。要找到A字符串与B字符串的最大字典序子串开始的位置。先输出A最大字典序子串的首个字符,然后一个个和B中的最大字典序串的头一个字符比较,若大,则继续输出,若小,则输出B最大字典序子串。详见代码。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pll;
template <typename T>
inline void rd(T& x)
{
	int tmp = 1; char c = getchar(); x = 0;
	while (c > '9' || c < '0') { if (c == '-')tmp = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	x *= tmp;
}
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int N = 3e5 + 10;
const int M=1e7+10;
const double eps=1e-8;
int len1,len2,pos1,pos2;
char s1[N],s2[N];
int main() {
//	ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
	scanf("%s %s",s1,s2);
	len1=strlen(s1);
	len2=strlen(s2);
	char max1=0,max2=0;
	for(int i=0;i<len1;i++){
		if(s1[i]>max1){
			max1=s1[i];
			pos1=i+1;
		}
		else if(s1[i]==max1&&i>0&&s1[i-1]!=max1){
			for(int j=1;j<=2*i-pos1+2;++j){
				if(s1[pos1-1+j]==s1[i+j]) continue;
				else if(s1[pos1-1+j]<s1[i+j]){
					pos1=i+1;
					break;
				}
				else break;
			}
		}
	}
	for(int i=0;i<len2;i++){
		if(s2[i]>max2){
			max2=s2[i];
			pos2=i;
		}
		else if(s2[i]==max2&&i>0&&s2[i-1]!=max2){
			for(int j=1;i+j<=2*i-pos2+1;++j){
				if(s2[pos2+j]==s2[i+j]) continue;
				else if(s2[pos2+j]<s2[i+j]){
					pos2=i;
					break;
				}
				else break;
			}
		}
	}
	printf("%c",max1);
	for(int i=pos1;i<len1;i++){
		if(s1[i]>=max2) printf("%c",s1[i]);
		else break;
	}
	for(int i=pos2;i<len2;i++){
		printf("%c",s2[i]);
	}
	return 0;  
}

D. Dice

这题首先比较容易想到的是使用余数来进行计数,最后 n n n个骰子的余数总和为0就是答案。
一开始没有别的想法,暴力 d p dp dp一波,结果还是 T T T
这道题首先的思路是,假如有两个骰子,结果余数 n u m [ ( i + j ) % m ] = n u m [ i ] ∗ n u m [ j ] num[(i+j)\%m]=num[i]*num[j] num[(i+j)%m]=num[i]num[j],由这个可以知道,是有关乘法的运算,面对这么庞大的数据,可以想到的是就是使用矩阵快速幂。
左边矩阵表示的是 当前 [ n u m 0 , n u m 1 , n u m 2 . . . . n u m k − 1 ] [num_0,num_1,num_2....num_{k-1}] [num0,num1,num2....numk1],右矩阵表示的是通过新的乘法得到新的左矩阵
右矩阵:
[ a 0 a 1 a 2 a . . . a m − 1 a m − 1 a 0 a 1 a . . . a m − 2 a m − 2 a m − 1 a 0 a . . . a m − 3 a . . . a . . . a . . . a . . . a . . . a 1 a 2 a 3 a . . . a 0 ] ( a i 表示数量 ) \left[ \begin{matrix} a_0 & a_{1} & a_{2} & a_{...} & a_{m-1}\\ a_{m-1} & a_{0} & a_{1} &a_{...} &a_{m-2}\\ a_{m-2} & a_{m-1} & a_{0} &a_{...} & a_{m-3}\\ a_{...} & a_{...} & a_{...} & a_{...} &a_{...}\\ a_{1} & a_{2} & a_{3} &a_{...} &a_{0} \end{matrix} \tag{$a_i$表示数量} \right] a0am1am2a...a1a1a0am1a...a2a2a1a0a...a3a...a...a...a...a...am1am2am3a...a0(ai)
详情见代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pll;
template <typename T>
inline void rd(T& x)
{
	ll tmp = 1; char c = getchar(); x = 0;
	while (c > '9' || c < '0') { if (c == '-')tmp = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	x *= tmp;
}
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int N = 2e4 + 1;
const int M=1e7+10;
const double eps=1e-8;
struct matrix{
	ll a[210][210];
	matrix(){
		memset(a,0,sizeof a);
	}
	matrix cal(const matrix &A,int n){
		matrix ans;
		for(int i=0;i<n;++i){
			for(int j=0;j<n;++j){
				for(int k=0;k<n;++k){
					ans.a[i][j]+=a[i][k]*A.a[k][j]%mod;
					ans.a[i][j]%=mod;
				}
			}
		}
		return ans;
	}
}; 
int num[200];
int n,k,m;
ll fp(ll x,ll y){
	ll ans=1;
	while(y){
		if(y&1) ans=ans*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ans;
}
ll solve(){
	matrix ans;
	for(int i=0;i<m;++i) ans.a[i][i]=1;
	matrix tmp;
	for(int i=0;i<m;++i){
		int pos=0;
		for(int j=i;j>=0;--j) tmp.a[pos++][i]=num[j];
		for(int j=m-1;;--j){
			if(pos==m) break;
			tmp.a[pos++][i]=num[j];
		}
	}
	while(n){
		if(n&1) ans=ans.cal(tmp,m);
		tmp=tmp.cal(tmp,m);
		n>>=1;
	}
	return ans.a[0][0];
}
int main() { 
	ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
	while(~scanf("%d %d %d",&n,&k,&m)){
		for(int i=0;i<m;++i){
			num[i]=k/m;
		}
		k%=m;
		for(int i=1;i<=k;++i) ++num[i];
		num[0]=0;
		ll ans=0;
		for(int i=1;i<m;++i) ans+=num[i];
		ans=fp(ans,n);
		printf("%lld\n",solve()*fp(ans,mod-2)%mod);
	}
	return 0;
}

E. Enter to the best problem of this contest!

一道简单交互题,首先询问第1号点,知道距离后询问下一层的左子树节点,如果返回距离减小,则在左子树的下一层询问,若返回距离增加,则在右子树的下一层询问,若返回距离增加且返回距离为2,则答案在同层同祖先的另一侧。若返回距离为0,则找到答案。详见代码。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pll;
template <typename T>
inline void rd(T& x)
{
	int tmp = 1; char c = getchar(); x = 0;
	while (c > '9' || c < '0') { if (c == '-')tmp = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	x *= tmp;
}
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int N = 1e5 + 10;
const int M=1e7+10;
const double eps=1e-8;
int n;
int query(int q){
	printf("%d\n",q);
	fflush(stdout);
	int k;
	scanf("%d",&k);
	return k;
}
int main() {
//	ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
	scanf("%d",&n);
	int temp=query(1),pos=1,ans;
	if(temp==0){
		printf("! 1\n");
		return 0;
	}
	while(1){
		temp--;
		ans=query(pos*2);
		if(ans==0){
			printf("! %d\n",pos*2);
			return 0;
		}
		else if(ans==temp) pos*=2;
		else if(temp==0&&ans==2){
			printf("! %d\n",pos*2+1);
			return 0;
		}
		else pos=pos*2+1;
	}
	return 0;  
}

F. Free restricted flights

这题是需要对每条边进行拆边,就每条边拆成

  • 付费边
  • 免费边,标序号 [ 1 , k ] [1,k] [1,k],表示是路途中第k个免费的边
    这题还有一个大坑点,k有可能用不完,意思就是路途全程都是免费的,真坑
    剩下的就是建边问题,对于后面返回原点的路径,直接建立反边从原点出发一个道理,并且当访问到一个点时已经用了 k 1 k_1 k1次免费机票,那么剩下的路径能使用的是 i ∈ [ 0 , k − k 1 ] i\in[0,k-k_1] i[0,kk1]个免费机票
    详情见代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pll;
template <typename T>
inline void rd(T& x)
{
	ll tmp = 1; char c = getchar(); x = 0;
	while (c > '9' || c < '0') { if (c == '-')tmp = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	x *= tmp;
}
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int N = 1e4 + 1;
const int M = 1e6 + 10;
const double eps = 1e-8;
struct edge {
	int next, to, w;
}e1[M], e2[M];
int head1[N*15], head2[N*15], cnt1, cnt2;
void add(edge e[], int head[], int& cnt, int u, int v, int w) {
	e[cnt].to = v;
	e[cnt].next = head[u];
	e[cnt].w = w;
	head[u] = cnt++;
}
int n, m, a, b, k;
int id[N][15];
ll dis1[N*15], dis2[N*15], dis3[N*15], dis4[N*15];
bool vis[N*15];
struct node {
	int v;
	ll len;
	bool friend operator<(const node& a, const node& b) {
		return a.len > b.len;
	}
	node(int v, ll len) :v(v), len(len) {}
};
void dijkstra(edge e[], int head[], int& cnt, ll dis[], int st) {
	for (int i = 0; i < N * 15; ++i) dis[i] = 1e16;
	dis[st] = 0;
	memset(vis, false, sizeof vis);
	priority_queue<node>que;
	que.push(node(st, 0));
	while (!que.empty()) {
		node vn = que.top(); que.pop();
		if (vis[vn.v]) continue;
		int u = vn.v;
		vis[u] = true;
		dis[u] = vn.len;
		for (int i = head[u]; ~i; i = e[i].next) {
			int v = e[i].to;
			if (vis[v]) continue;
			que.push(node(v, vn.len + e[i].w));
		}
	}
}
int main() {
	ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
	memset(head1, -1, sizeof head1); memset(head2, -1, sizeof head2); cnt1 = cnt2 = 0;
	rd(n), rd(m), rd(a), rd(b), rd(k);
	int num = 0;
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j <= k; ++j) {
			id[i][j] = ++num;
		}
	}
	while (m--) {
		int u, v, w; rd(u), rd(v),rd(w);
		for (int j = 0; j < k; ++j) {
			add(e1, head1, cnt1, id[u][j], id[v][j], w);
			add(e1, head1, cnt1, id[u][j], id[v][j + 1], 0);
			add(e2, head2, cnt2, id[v][j], id[u][j], w);
			add(e2, head2, cnt2, id[v][j], id[u][j + 1], 0);
		}
		add(e1, head1, cnt1, id[u][k], id[v][k], w);
		add(e2, head2, cnt2, id[v][k], id[u][k], w);
	}
	dijkstra(e1, head1, cnt1, dis1, id[a][0]);
	dijkstra(e1, head1, cnt1, dis2, id[b][0]);
	dijkstra(e2, head2, cnt2, dis3, id[a][0]);
	dijkstra(e2, head2, cnt2, dis4, id[b][0]);
	int pos = -1; ll ans = 1e16;
	for (int i = 0; i < n; ++i) {
		if (a == i || b == i) continue;
		ll ans1 = 1e16, ans2 = 1e16;
		for (int j1 = 0; j1 <= k; ++j1) {
			for (int j2 = 0; j2 <= k - j1; ++j2) {
				int v1 = id[i][j1];
				int v2 = id[i][j2];
				if (ans1 > dis1[v1] + dis3[v2]) {
					ans1 = dis1[v1] + dis3[v2];
				}
				if (ans2 > dis2[v1] + dis4[v2]) {
					ans2 = dis2[v1] + dis4[v2];
				}
			}
		}
		if (ans > ans1 + ans2) {
			ans = ans1 + ans2;
			pos = i;
		}
	}
	if (ans == 1e16) puts(">:(");
	else printf("%d %lld\n", pos, ans);
	return 0;
}

G. Great dinner

这题不用管后面给出哪两个数字前后关系,只要知道有多少对就行了
首先 令 k k k是剩下的没有限制关系的成员 , a n s = A k k ans=A_{k}^{k} ans=Akk
k 1 k_1 k1是当前已经排好序的人员数量,则新一对的加入到队伍中的情况总数是 [ ( 1 + k 1 ) + 1 ] ∗ ( 1 + k 1 ) 2 \frac{[(1+k_1)+1]*(1+k_1)}{2} 2[(1+k1)+1](1+k1)
详情见代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pll;
template <typename T>
inline void rd(T& x)
{
	int tmp = 1; char c = getchar(); x = 0;
	while (c > '9' || c < '0') { if (c == '-')tmp = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	x *= tmp;
}
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
const int M = 1e7 + 10;
const double eps = 1e-8;
ll n, m;
ll bully[N], victim[N];
ll fac[N];
ll get(ll x) {
	ll ans = 1;
	if (x & 1) ans = ans * (1 + x) / 2 % mod * x % mod;
	else ans = ans * x / 2 % mod * (1 + x) % mod;
	return ans % mod;
}
int main() {
	ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
	fac[0] = 1;
	for (int i = 1; i <= N; ++i) fac[i] = fac[i - 1] * i % mod;
	rd(n), rd(m);
	for (int i = 1; i <= m; i++) {
		scanf("%lld %lld", &bully[i], &victim[i]);
	}
	m <<= 1;
	ll ans = fac[n - m];
	m >>= 1;
	for (int i = 0; i < m; ++i) {
		ans = ans * get(n - m * 2 + i * 2 + 1) % mod;
	}
	printf("%lld\n", ans);
	return 0;
}

K. Katastrophic sort

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pll;
template <typename T>
inline void rd(T& x)
{
	ll tmp = 1; char c = getchar(); x = 0;
	while (c > '9' || c < '0') { if (c == '-')tmp = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	x *= tmp;
}
const ll inf = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const ll N = 2e3 + 10;
const ll M = 1e7 + 10;
const double eps = 1e-8;
string s1, s2;
int check(string x, string y) {
	int len1 = x.size(), len2 = y.size();
	for (int i = 0; i < len1 && i < len2; ++i) {
		if (x[i] != y[i]) {
			if (x[i] < y[i]) return -1;
			else return 1;
		}
	}
	if (len1 == len2) return 0;
	else if (len1 < len2) return -1;
	else return 1;
}
int check1(string x, string y) {
	int len1 = x.size(), len2 = y.size();
	if (len1 != len2) {
		if (len1 < len2) return -1;
		else return 1;
	}
	for (int i = 0; i < len1 && i < len2; ++i) {
		if (x[i] != y[i]) {
			if (x[i] < y[i]) return -1;
			else return 1;
		}
	}
	return 0;
}
int main() {
	ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
	cin >> s1 >> s2;
	string x = "", y = ""; int posx = 0, posy = 0;
	for (int i = 0; i < s1.size(); ++i) {
		if (!isalpha(s1[i])) {
			posx = i;
			break;
		}
		x += s1[i];
	}
	for (int i = 0; i < s2.size(); ++i) {
		if (!isalpha(s2[i])) {
			posy = i;
			break;
		}
		y += s2[i];
	}
	int tmp = check(x, y);
	if (tmp > 0) puts(">");
	else if (tmp < 0) puts("<");
	else {
		string xx = "", yy = "";
		for (int i = posx; i < s1.size(); ++i) {
			xx += s1[i];
		}
		for (int i = posy; i < s2.size(); ++i) {
			yy += s2[i];
		}
		int tmp = check1(xx, yy);
		if (tmp > 0) puts(">");
		else if (tmp < 0) puts("<");
		else puts("=");
	}
	return 0;
}

L.Lonely day

题意:给定一个 n ∗ m n*m nm的矩阵。矩阵中有四种元素。
. . . : 可以通过。
X X X : 不可通过。
S S S : 起点。
E E E : 终点。
找出一种字典序最小的方法从 S S S走到 E E E。输出步数输出这个走法,若没有解则输出 − 1 -1 1
有四种走法。
D D D : 向下走。
L L L : 向左走。
R R R : 向右走。
U U U : 向上走。
有两种方法可以到 . . .元素,符号 M M M表示现在所在的位置。
[ M . ] (1) \left[ \begin{matrix} M & . \\ \end{matrix} \right] \tag{1} [M.](1)
此时 M M M可以走到 . . .

[ M X . . . . . . X . ] (2) \left[ \begin{matrix} M & X & ...... & X & . \\ \end{matrix} \right] \tag{2} [MX......X.](2)
此时 M M M可以走到 . . .
题解:使用 B F S BFS BFS来解决最短路径的问题(因为太菜导致一开始想的时候居然使用了 D F S DFS DFS)。按照 D D D L L L R R R U U U的顺序依次搜索(这样就能保证第一个解必定是字典序最小的)。并且使用两个二维前驱数组来保存搜索过的路径。这两个数组分别为 x _ p r e [ ] [ ] x\_pre[][] x_pre[][] y _ p r e [ ] [ ] y\_pre[][] y_pre[][],前者保存当前点的前驱点的 x x x坐标,后者保存当前点的前驱点的 y y y坐标。找到解后即可直接使用 D F S DFS DFS回溯查找路径并结束 B F S BFS BFS
切记要使用一个布尔类型的 v i s [ ] [ ] vis[][] vis[][]输出来保证入队列的点不会被重复访问到。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int NN = 2e3 + 5;
struct Node {
    int x, y;
};
int n, m, sx, sy, ex, ey, num;
int dir[4][2] = {{1, 0}, {0, -1}, {0, 1}, {-1, 0}};
int x_pre[NN][NN], y_pre[NN][NN];
char ans[NN * 2];
char str[NN][NN];
bool vis[NN][NN];
void init() {}
void dfs_ans(int x, int y) {
    if (x == sx && y == sy) {
        cout << num << endl;
        for (int i = num - 1; i >= 0; i--)
            cout << ans[i];
        puts("");
        return;
    }
    int xx = x_pre[x][y], yy = y_pre[x][y];
    if (yy == y) {
        if (xx > x)
            ans[num++] = 'U';
        else
            ans[num++] = 'D';
    } else if (xx == x) {
        if (yy > y)
            ans[num++] = 'L';
        else
            ans[num++] = 'R';
    }
    dfs_ans(xx, yy);
}
void bfs() {
    queue<Node> q;
    q.push({sx, sy});
    vis[sx][sy] = true;
    while (!q.empty()) {
        Node u = q.front();
        q.pop();
        if (u.x == ex && u.y == ey) {
            dfs_ans(ex, ey);
            return;
        }
        for (int i = 0; i < 4; i++) {
            int xx = u.x, yy = u.y;
            while (1) {
                xx += dir[i][0];
                yy += dir[i][1];
                if (xx < 1 || xx > n || yy < 1 || yy > m || vis[xx][yy])
                    break;
                if (str[xx][yy] == '.') {
                    vis[xx][yy] = true;
                    q.push({xx, yy});
                    x_pre[xx][yy] = u.x;
                    y_pre[xx][yy] = u.y;
                    break;
                }
            }
        }
    }
    printf("-1\n");
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            cin >> str[i][j];
            if (str[i][j] == 'S') {
                sx = i;
                sy = j;
                str[i][j] = '.';
            } else if (str[i][j] == 'E') {
                ex = i;
                ey = j;
                str[i][j] = '.';
            }
        }
    bfs();
    return 0;
}

M. Magic spells

普通的二分查找,将每个字母的下标存进vector里,查找的时候尽量往最左边查找,找不到就返回答案。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pll;
template <typename T>
inline void rd(T& x)
{
	ll tmp = 1; char c = getchar(); x = 0;
	while (c > '9' || c < '0') { if (c == '-')tmp = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	x *= tmp;
}
const ll inf = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const ll N = 2e3 + 10;
const ll M = 1e7 + 10;
const double eps = 1e-8;
string s;
vector<int>vec[30];
int len;
string check(string x) {
	if (vec[x[0] - 'a'].empty()) return "IMPOSSIBLE";
	int len1 = x.size(), pos = vec[x[0] - 'a'][0];
	string ans = "";
	ans += x[0];
	for (int i = 1; i < len1; ++i) {
		int ansn = -1;
		int l = 0, r = vec[x[i] - 'a'].size() - 1;
		while (l <= r) {
			int mid = l + r >> 1;
			if (vec[x[i] - 'a'][mid] > pos) {
				r = mid - 1;
				ansn = mid;
			}
			else l = mid + 1;
		}
		if (ansn == -1) return ans;
		pos = vec[x[i] - 'a'][ansn];
		ans += x[i];
	}
	return ans;
}
int main() {
	ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
	cin >> s;
	len = s.size();
	for (int i = 0; i < len; ++i) {
		vec[s[i] - 'a'].push_back(i);
	}
	int n; rd(n);
	while (n--) {
		string x;
		cin >> x;
		cout << check(x) << endl;
	}
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值