ABC268 题解

比赛链接:https://atcoder.jp/contests/abc268/tasks

题解:
C
对于每个盘子统计一下转那几次(3 种情况)能够满足条件

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define pii pair<int,int>
#define pb push_back

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 2e5+5;

int n,a[maxn],cnt[maxn];

signed main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++)scanf("%d",&a[i]);
	for(int i=0;i<n;i++){
		int now = (a[i]-i+n)%n;
		++ cnt[now%n];
		++ cnt[(now+1)%n];
		++ cnt[(now+n-1)%n];
	}
	int ans = 0;
	for(int i=0;i<n;i++)
		ans = max(ans, cnt[i]);
	cout << ans << '\n';

	return 0;
}

D
\(O(n!)\) 爆搜一下,注意每次下划线的个数和之后单词的个数有关,用 map 判重即可

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define pii pair<int,int>
#define pb push_back

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f;

int n,m;
set<string>S;
string s[12];
int vis[12];

void dfs(int x,int rem,string now=""){
	if(x == n+1){
		if(now.size()<3||now.size()>16)return ;
		if(S.count(now))return ;
		cout << now << '\n';
		exit(0);
	}
	for(int i=1;i<=n;i++)if(!vis[i]){
		vis[i] = 1;
		string nn = now+s[i];
		if(x==n)dfs(x+1,rem,nn);
		else{
			for(int un=1;un<=rem;un++)if(un+n-x-1<=rem){
				nn = nn + '_';
				dfs(x+1,rem-un,nn);
			}
		}
		vis[i] = 0;
	}
}

signed main(){
	scanf("%d%d",&n,&m);
	int sz = 0;
	for(int i=1;i<=n;i++){
		cin >> s[i];
		sz += s[i].size();
	}
	for(int i=0;i<m;i++){
		string t;
		cin >>t;
		S.insert(t);
	}
	dfs(1,16-sz,"");
	puts("-1");

	return 0;
}

E
坑了

F
贪心的交换法,比 E 简单

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define pii pair<int,int>
#define pb push_back

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn=2e5+5;

int n;
string s[maxn];
int sum[maxn],sum2[maxn],id[maxn];

signed main(){
	cin.tie(0);ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;i++){
		id[i] = i;
		cin>>s[i];
		for(int j=0;j<s[i].size();j++){
			if(s[i][j]=='X')++sum[i];
			else sum2[i]+=s[i][j]-'0';
		}
	}
	sort(id+1,id+n+1,[&](int x,int y){
		return 1ll*sum[x]*sum2[y]>1ll*sum[y]*sum2[x];
	});
	int cx = 0;
	ll ans=0;
	for(int i=1;i<=n;i++){
		string nt = s[id[i]];
		for(int j=0;j<nt.size();j++){
			if(nt[j] == 'X')++cx;
			else{
				ans += 1ll*cx*(nt[j]-'0');
			}
		}
	}
	cout << ans << '\n';

	return 0;
}

G
“脑筋急转弯”
首先,\(E(rank_i)=1+E(rank_j<rank_i)=1+\sum_jPr(rank_j<rank_i)\)
考虑 \(i,j\) 的关系:如果 \(j\)\(i\) 的前缀,显然 \(Pr=0\)
如果 \(i\)\(j\) 的前缀,显然 \(Pr=1\)
否则,\(Pr=1/2\),因为考虑第一个 \(i,j\) 不同的位置,显然大于和小于的方案数是对称相等的,因此为 \(1/2\)
写个 trie 判一下前缀关系即可

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define pii pair<int,int>
#define pb push_back

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 5e5+5, mod = 998244353;
const int inv2 = (mod+1)/2;

int n;
char s[maxn];
struct trie{
	int tr[maxn][27], cnt = 0, pos[maxn*26], sz[maxn*26];
	int mp[maxn * 26];
	void insert(char *s,int id){
		int n=strlen(s+1);
		int p = 0;
		for(int i=1;i<=n;i++){
			int t = s[i] - 'a';
			if(!tr[p][t]){
				tr[p][t] = ++cnt;
			}
			p = tr[p][t];
		}
		++ pos[p];
		mp[p] = id;
	}
	
	int ans[maxn];
	void dfs(int x,int pref=0,int id=0){
//		printf("%d %d %d\n",x,pref,id);
		int p = x;
		sz[p] = pos[p];
		for(int i=0;i<26;i++)if(tr[p][i]){
			dfs(tr[p][i], pref+pos[p], mp[tr[p][i]]?mp[tr[p][i]]:0);
			sz[p] += sz[tr[p][i]];
		}
//		printf("? %d %d %d   %d %d\n",p,id,sz[p],(n-pref-sz[p]),pref);
		if(id)(ans[id] = 1ll*(n-pref-sz[p])*inv2%mod + (pref)%mod + 1) %= mod; 
	}
}tr;

signed main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%s",s +1);
		tr.insert(s, i);
	}
	tr.dfs(0);
	for(int i=1;i<=n;i++)printf("%d\n",tr.ans[i]);

	return 0;
}

Ex
建出 AC 自动机之后贪心即可,如果当前位能匹配上而且是末尾,就改成 *

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define pii pair<int,int>
#define pb push_back

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn=1e6+5;

struct AC{
	int lst[maxn];
	int tr[maxn][27],cnt;
	int val[maxn];	// 多少个以 i 结点结尾的单词 
	int fail[maxn];
	
	AC(){cnt=0;memset(val,0,sizeof val);}
	
	void insert(char *s){
		int p=0;
		int ns = strlen(s + 1);
		for(int i=1;i<=ns;i++){
			int k = s[i] - 'a';
			if(!tr[p][k])tr[p][k] = ++ cnt;
			p = tr[p][k];
		}
		++ val[p];
	}
	
	void build(){
		queue<int>Q;
		Q.push(0);
		while(!Q.empty()){
			int u = Q.front();Q.pop();
			for(int i=0;i<26;i++)
				if(tr[u][i]){
					fail[tr[u][i]] = u ? tr[fail[u]][i] : 0;
					if(val[fail[tr[u][i]]])lst[tr[u][i]] = fail[tr[u][i]];
					else lst[tr[u][i]] = lst[fail[tr[u][i]]];
					
					Q.push(tr[u][i]);
				}else tr[u][i] = tr[fail[u]][i];
		}
	}
	
	void query(char *t){
		int p=0, res=0;
		int nt = strlen(t + 1);
		for(int i=1;i<=nt;i++){
			p = tr[p][t[i] - 'a'];
			int fg = 0;
			if(val[p]){
				fg = 1;
			}
			
			int v = lst[p];
			while(v){	// 沿失配边跳,加上abc bc c这种的匹配 
				if(val[v]){
					fg = 1;
				}
				v = lst[v];
			}
			if(fg){
				++ res;
				p = 0;
			}
		}
		printf("%d\n",res);
	}
}ac;
char s[maxn],t[maxn];
int n;

signed main(){
	scanf("%s",t+1);
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%s",s +1);
		ac.insert(s);
	}
	ac.build();
	ac.query(t);

	return 0;
}
posted @ 2023-02-12 11:50  SkyRainWind  阅读(24)  评论(0编辑  收藏  举报