关于此题的神必dp做法
查看原帖
关于此题的神必dp做法
856488
XYstarabyss楼主2025/7/22 16:57

rt,因为我太蒻了,所以看到这一题想不到正解,只知道要用 ACAM。所以直接糊了一个公式的 ACAM 上套 dp 的做法上去。

然后……就差一个 hack 点 A 掉此题???

神必 dp 做法展示 ↓

#include<bits/stdc++.h>
using namespace std;
#define f(n,m,i) for(register int i(n);i<=m;++i)
#define nf(n,m,i) for(register int i(n);i>=m;--i)
#define dbug(x) cerr<<(#x)<<':'<<x<<' ';
#define ent cerr<<'\n';
#define ll long long
#define C cerr.tie(0),cout.tie(0),cin.tie(0)->sync_with_stdio(false);
constexpr int N(30005),mod(10007);
int n,m,dp[805][N],res(0);
string ps;
namespace AC{
	int tot;
	struct Node{
		int s[2],cnt,fl,id;//子节点,匹配计数,fail指针,结束编号
		void init(){	memset(s,0,sizeof s),cnt=fl=id=0;}
	}t[N];
	void ins(string c){
		int x(0);
		f(0,c.length()-1,i){
			int &y(t[x].s[c[i]-'0']);
			if (!y)	y=++tot,t[y].init();
			x=y;
		}
		t[x].id=1;
	}
	void bld(){
		queue<int>q;
		f(0,1,i)	if (t[0].s[i])	q.push(t[0].s[i]);
		while (!q.empty()){
			int x(q.front());
			q.pop();
			f(0,1,i){
				if (t[x].s[i]){
					t[t[x].s[i]].id|=t[t[t[x].fl].s[i]].id;
					t[t[x].s[i]].fl=t[t[x].fl].s[i];
					q.push(t[x].s[i]);
				}
				else	t[x].s[i]=t[t[x].fl].s[i];
			}
		}
	}
}
using namespace AC;
int main(){ C
	tot=0,t[0].init();
	cin>>n,m=800;
	f(1,n,i)	cin>>ps,ins(ps);
	bld();
	dp[0][0]=1;
	f(1,m,i)
		f(0,tot,j)
			f(0,1,k)
				if(!t[t[j].s[k]].id)
					dp[i][t[j].s[k]]|=dp[i-1][j];
	f(0,tot,j)	res|=dp[m][j];
	if(res)	cout<<"TAK\n";
	else	cout<<"NIE\n";
	return 0;
}

但是用 ST(subtask)分治骗过那一个点的做法还是有点低能了,于是开始思考有没有方法能光明正大直接A掉此题。

不难发现考虑的 m 还是太小了,至少应该达到所有病毒片段的长度之和才行,但是这样的话会时空双响炮。然而,我还是抱着试一试的心态给 dp 数组滚了一下,时间就不管啦。

然后……过了???同时喜提一个最劣解

神必 AC dp 做法展示↓

#include<bits/stdc++.h>
using namespace std;
#define f(n,m,i) for(register int i(n);i<=m;++i)
#define nf(n,m,i) for(register int i(n);i>=m;--i)
#define dbug(x) cerr<<(#x)<<':'<<x<<' ';
#define ent cerr<<'\n';
#define ll long long
#define C cerr.tie(0),cout.tie(0),cin.tie(0)->sync_with_stdio(false);
constexpr int N(30005);
int n,m,dp[2][N],res(0);
string ps;
namespace AC{
	int tot;
	struct Node{
		int s[2],cnt,fl,id;//子节点,匹配计数,fail指针,结束编号
		void init(){	memset(s,0,sizeof s),cnt=fl=id=0;}
	}t[N];
	void ins(string c){
		int x(0);
		f(0,c.length()-1,i){
			int &y(t[x].s[c[i]-'0']);
			if (!y)	y=++tot,t[y].init();
			x=y;
		}
		t[x].id=1;
	}
	void bld(){
		queue<int>q;
		f(0,1,i)	if (t[0].s[i])	q.push(t[0].s[i]);
		while (!q.empty()){
			int x(q.front());
			q.pop();
			f(0,1,i){
				if (t[x].s[i]){
					t[t[x].s[i]].id|=t[t[t[x].fl].s[i]].id;
					t[t[x].s[i]].fl=t[t[x].fl].s[i];
					q.push(t[x].s[i]);
				}
				else	t[x].s[i]=t[t[x].fl].s[i];
			}
		}
	}
}
using namespace AC;
int main(){ C
	tot=0,t[0].init();
	cin>>n;
	f(1,n,i)	cin>>ps,m+=ps.length(),ins(ps);
	bld();
	dp[0][0]=1;
	f(1,m,i){
		f(0,tot,j)
			f(0,1,k)
				if(!t[t[j].s[k]].id)
					dp[i&1][t[j].s[k]]|=dp[~i&1][j];
		f(0,tot,j)	dp[~i&1][j]=0;
	}
	f(0,tot,j)	res|=dp[m&1][j];
	if(res)	cout<<"TAK\n";
	else	cout<<"NIE\n";
	return 0;
}

因此,建议加强本题数据卡掉这种神必做法

2025/7/22 16:57
加载中...