2019.7.23模拟赛

T1 序列

写过的第一个迭代加深搜索,自然在考场上是想不出来的qwq

首先枚举答案,然后有一个核心函数:估价函数,用来估计离终点还有多远。

为了答案的准确性,估价函数\(g(x)\)和真正的距离函数\(f(x)\)需要满足\(g(x)\le f(x)\),同时为了速度,\(f(x)\)\(g(x)\)需要尽量接近。

在这题里面,我们注意到每换一次最多只会改变一对相邻数之差的绝对值,所以可以设\(g(x)\)表示相邻数之差不为1的个数。

然后,我们开始搜索。当发现\(dep+g(x)>mxdep\)的时候就直接返回,顺便再加个不能连续翻转同一块的剪枝,于是就跑得飞快了。

#include<bits/stdc++.h>
using namespace std;
#define rep(i,x,y) for (int i=(x);i<=(y);++i)
#define drep(i,y,x) for (int i=(y);i>=(x);--i)
#define temp template<typename T>
temp bool chkmax(T &x,T y){return x<y?x=y,1:0;}
temp bool chkmin(T &x,T y){return x>y?x=y,1:0;}
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
temp void read(T &x)
{
	x=0;char ch=getchar(),t=0;
	while (ch>'9'||ch<'0') t|=(ch=='-'),ch=getchar();
	while (ch<='9'&&ch>='0') x=x*10+ch-48,ch=getchar();
	if (t) x=-x;
}
void file()
{
	#ifdef NTFAKIOI
	freopen("a.in","r",stdin);
	#endif
}
#define db double
#define ll long long
#define sz 25

int n;
vector<int>a,cur;
int mxdep;bool flg;
void dfs(int dep,int lst)
{
	if (dep>mxdep||flg) return;
	if (cur==a) return (void)(flg=1);
	int cc=0;
	rep(i,0,n-2) if (abs(cur[i+1]-cur[i])>1) ++cc;
	if (dep+cc>mxdep) return;
	rep(i,1,n-1) 
		if (i!=lst&&!flg) 
			reverse(cur.begin(),cur.begin()+i+1),dfs(dep+1,i),reverse(cur.begin(),cur.begin()+i+1);
}

void work()
{
	read(n);a.resize(n);cur.resize(n);
	rep(i,0,n-1) read(cur[i]),a[i]=i+1;
	flg=0;
	rep(i,0,1e9) 
	{
		mxdep=i;
		dfs(0,-1);
		if (flg) return (void)(cout<<i<<'\n');
	}
}

int main()
{
	file();
	int T;read(T);
	while (T--) work();
	return 0;
}

T2 轰炸

容易发现就是个最小反链覆盖,然而我把dilworth定理给忘了,而旁边的神仙个个都切了,于是就猜了个最长链的结论,顺便用数学归纳法伪证了一下,就过了。

#include<bits/stdc++.h>
using namespace std;
#define rep(i,x,y) for (int i=(x);i<=(y);++i)
#define drep(i,y,x) for (int i=(y);i>=(x);--i)
#define temp template<typename T>
temp bool chkmax(T &x,T y){return x<y?x=y,1:0;}
temp bool chkmin(T &x,T y){return x>y?x=y,1:0;}
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
temp void read(T &x)
{
	x=0;char ch=getchar(),t=0;
	while (ch>'9'||ch<'0') t|=(ch=='-'),ch=getchar();
	while (ch<='9'&&ch>='0') x=x*10+ch-48,ch=getchar();
	if (t) x=-x;
}
void file()
{
	#ifdef NTFAKIOI
	freopen("a.in","r",stdin);
	#endif
}
#define db double
#define ll long long
#define sz 1010101
#define v edge[i].t
#define go(x) for (int i=head[x];i;i=edge[i].nxt)

int n,m;
struct hh{int t,nxt;}edge[sz<<1];
int head[sz],ecnt;
int deg[sz];
void make_edge(int f,int t){edge[++ecnt]=(hh){t,head[f]};head[f]=ecnt;++deg[t];}
int w[sz];
int dp[sz];

void solve()
{
	queue<int>q;
	rep(i,1,n) if (!deg[i]) q.push(i),dp[i]=w[i];
	while (!q.empty())
	{
		int x=q.front();q.pop();
		go(x)
		{
			chkmax(dp[v],dp[x]+w[v]);
			if (!--deg[v]) q.push(v);
		}
	}
	int ans=0;
	rep(i,1,n) chkmax(ans,dp[i]);
	cout<<ans;
}

namespace Build
{
	int n,m;
	struct hh{int t,nxt;}edge[sz<<1];
	int head[sz],ecnt;
	void make_edge(int f,int t){edge[++ecnt]=(hh){t,head[f]};head[f]=ecnt;}
	int dfn[sz],low[sz],cnt;
	stack<int>st;
	bool in[sz];
	int bel[sz],T;
	void tarjan(int x)
	{
		dfn[x]=low[x]=++cnt;in[x]=1;st.push(x);
		go(x) 
		{
			if (!dfn[v]) tarjan(v),chkmin(low[x],low[v]);
			else if (in[v]) chkmin(low[x],dfn[v]);
		}
		if (dfn[x]==low[x])
		{
			++T;int y;
			do
			{
				y=st.top();st.pop();in[y]=0;
				++w[T];bel[y]=T;
			}while (y!=x);
		}
	}
	void solve()
	{
		read(n),read(m);
		int x,y;
		rep(i,1,m) read(x),read(y),make_edge(x,y);
		rep(i,1,n) if (!dfn[i]) tarjan(i);
		rep(x,1,n) go(x) if (bel[x]!=bel[v]) ::make_edge(bel[x],bel[v]);
		::n=T;
	}
}

int main()
{
	file();
	Build::solve();
	solve();
	return 0;
}

T3 字符串

前几天刚口胡过类似的题,所以基本上看完题就会了。

就是分类讨论,有三种可能:在左边,在右边,被切成两半。

所以我们建出原串和翻转+反转之后的串的AC自动机,就可以设\(dp_{i,S,x}\)表示前\(i\)位,搞定了\(S\)串,AC自动机上跑到了\(x\),的方案数,然后随便DP。

统计答案的时候判一下左右接在一起能不能搞出其他串,就可以了。

#include<bits/stdc++.h>
using namespace std;
#define rep(i,x,y) for (int i=(x);i<=(y);++i)
#define drep(i,y,x) for (int i=(y);i>=(x);--i)
#define temp template<typename T>
temp bool chkmax(T &x,T y){return x<y?x=y,1:0;}
temp bool chkmin(T &x,T y){return x>y?x=y,1:0;}
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
temp void read(T &x)
{
	x=0;char ch=getchar(),t=0;
	while (ch>'9'||ch<'0') t|=(ch=='-'),ch=getchar();
	while (ch<='9'&&ch>='0') x=x*10+ch-48,ch=getchar();
	if (t) x=-x;
}
void file()
{
	#ifdef NTFAKIOI
	freopen("a.in","r",stdin);
	#endif
}
#define db double
#define ll long long
#define sz 1266
#define mod 998244353ll

int n;
char s[8][sz];
int m;

ll dp[2][70][sz];

int root=0,cnt;
int ch[sz][2],fail[sz],msk[sz],msk2[sz];
void insert(int id,char *s)
{
	int n=strlen(s+1),x=root;
	rep(i,1,n)
	{
		int &v=ch[x][s[i]-'0'];
		if (!v) v=++cnt;
		x=v;
	}
	msk[x]|=(1<<(id-1));
}
void getfail()
{
	queue<int>q;
	rep(i,0,1) if (ch[0][i]) q.push(ch[0][i]);
	while (!q.empty())
	{
		int x=q.front();q.pop();
		msk[x]|=msk[fail[x]],msk2[x]|=msk2[fail[x]];
		rep(i,0,1)
		{
			int &v=ch[x][i];
			if (v) fail[v]=ch[fail[x]][i],q.push(v);
			else v=ch[fail[x]][i];
		}
	}
}

int main()
{
	file();
	read(n),read(m);
	rep(i,1,n)
	{
		cin>>(s[i]+1);
		insert(i,s[i]);
		int l=strlen(s[i]+1);
		rep(k,1,l) s[i][k]^=1;
		reverse(s[i]+1,s[i]+l+1);
		insert(i,s[i]);
		rep(k,1,l) s[i][k]^=1;
		reverse(s[i]+1,s[i]+l+1);
		rep(k,1,l-1)
		{
			bool flg=1;
			if (k<=l/2)
			{
				rep(t,1,k) flg&=(s[i][t]!=s[i][2*k-t+1]);
				if (!flg) continue;
				int x=root;
				drep(t,l,k+1) x=ch[x][(s[i][t]-'0')^1];
				msk2[x]|=(1<<(i-1));
			}
			else
			{
				rep(t,k+1,l) flg&=(s[i][t]!=s[i][2*k-t+1]);
				if (!flg) continue;
				int x=root;
				rep(t,1,k) x=ch[x][s[i][t]-'0'];
				msk2[x]|=(1<<(i-1));
			}
		}
	}
	getfail();
	int cur=0,lst=1;
	dp[0][0][0]=1;
	int S=(1<<n)-1;
	rep(i,0,m-1)
	{
		swap(cur,lst);
		rep(s,0,S) rep(x,0,cnt) dp[cur][s][x]=0;
		rep(s,0,S) rep(x,0,cnt) rep(t,0,1)
		{
			ll w=dp[lst][s][x];
			(dp[cur][s|msk[ch[x][t]]][ch[x][t]]+=w)%=mod;
		}
	}
	ll ans=0;
	rep(s,0,S) rep(x,0,cnt) if ((s|msk2[x])==S) (ans+=dp[cur][s][x])%=mod;
	cout<<ans;
	return 0;
}
posted @ 2019-07-23 15:22  p_b_p_b  阅读(180)  评论(0编辑  收藏  举报