8.10 NOI 模拟赛 ldysb dp套dp dp

LINK:ldysb

avatar
avatar

其实我不会这道题的正解 题解就来了一句dp套dp 只有STD的我 无能为力.

这里写主要是因为考试的时候连40分的暴力都打不出来.

先考虑20分的暴力.

可以得知 每次必然是从 3,5,7...这些地方点的.

而且顺序满足 点过后面的前面就点不了了.

所以可以\(f_{i,j}\)表示前i个能否形成字符j.

暴力枚举转移就是n^2的.

考虑怎么线性判断.

从前往后 那么就有因为不知道后面的给的是0还是1 而无法判断.

我们考虑设计状态来解决这个情况.

想解决这个问题 需要暴力枚举下一位是什么,有\(f_{i,j}\)表示 到了第i个位置下一位是j 那么前面的能变成什么.

然后可能变成0/1 再开一维记录即可.

这样就把所有的情况给压缩起来了.

算是一个套路吧 状态中暴力枚举下一次的状态来进行dp.

score 40
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<queue>
#include<deque>
#include<stack>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000
#define inf 1000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(p,n,i) for(RE int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define fep(n,p,i) for(RE int i=n;i>=p;--i)
#define vep(p,n,i) for(RE int i=p;i<n;++i)
#define pii pair<int,int>
#define mk make_pair
#define RE register
#define P 13331ll
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define EPS 1e-5
#define sq sqrt
#define S second
#define F first
#define mod 1000000007
#define md 998244353
#define max(x,y) ((x)<(y)?y:x)
#define l(i) t[i].l
#define r(i) t[i].r
#define mx(i) t[i].mx
#define w(i) t[i].w
#define zz p<<1
#define yy p<<1|1
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
	return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
	RE int x=0,f=1;RE char ch=getc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
	return x*f;
}
inline ll Read()
{
	RE ll x=0,f=1;RE char ch=getc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
	return x*f;
}
const int MAXN=100010;
int T,n;
char a[MAXN];
int w[8];
int b[MAXN];
int f[MAXN][2][2];
int main()
{
	freopen("ldysb.in","r",stdin);
	freopen("ldysb.out","w",stdout);
	scanf("%d",&T);
	while(T--)
	{
		scanf("%s",a+1);
		
		w[0]=a[1]-'0';
		w[4]=a[2]-'0';
		w[2]=a[3]-'0';
		w[6]=a[4]-'0';
		w[1]=a[5]-'0';
		w[5]=a[6]-'0';
		w[3]=a[7]-'0';
		w[7]=a[8]-'0';
		scanf("%s",a+1);
		n=strlen(a+1);
		
		if(n==1&&a[1]=='1'){puts("1");continue;}
		if(n<=2){puts("0");continue;}		
		rep(1,n,i)
		{
			if(a[i]=='?')return 0;
			f[i][0][0]=f[i][0][1]=0;
			f[i][1][0]=f[i][1][1]=0;
			b[i]=a[i]-'0';
		}
		f[2][0][w[b[1]<<2|b[2]<<1]]=1;
		f[2][1][w[b[1]<<2|b[2]<<1|1]]=1;
		for(int i=4;i<=n;i+=2)
		{
			//merge
			int ww;
			rep(0,1,j)
			{
				if(!f[i-2][b[i-1]][j])continue;
				//j a[i]
				f[i][0][w[j<<2|b[i]<<1]]=1;
				f[i][1][w[j<<2|b[i]<<1|1]]=1;
			}
			//not merge
			rep(0,1,j)
			{
				// a[i-1] a[i] j
				ww=w[b[i-1]<<2|b[i]<<1|j];
				rep(0,1,k)if(f[i-2][ww][k])f[i][j][k]=1;
			}
		}
		put(f[n-1][b[n]][1]);
	}
	return 0;
}

统计方案数需要dp套dp 学过但不太会 自闭.

std
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=100010,mod=998244353;
#define MP make_pair
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline int read(){
    int x=0,f=0;char ch=getchar();
    while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
int n,p[maxn],s[maxn],to[16][2][2],f[maxn][16];
char str[maxn];
inline void qmo(int &x){x+=(x>>31?mod:0);}
void solve(){
	scanf("%s",str);
	FOR(i,0,7) p[i]=str[i]-'0';
	FOR(i,0,16) FOR(s1,0,1) FOR(s2,0,1){
		int s=0;
		FOR(k,0,1){
			s|=((i>>(k<<1|s1))&1)<<(p[s2<<1|k]<<1);
			s|=((i>>(k<<1|s1))&1)<<(p[s2<<1|k|4]<<1|1);
			s|=((i>>(k<<1|p[s2<<1|s1]))&1)<<(k<<1);
			s|=((i>>(k<<1|p[s2<<1|s1|4]))&1)<<(k<<1|1);
		}
		to[i][s1][s2]=s;
	}
	scanf("%s",str+1);
	n=strlen(str+1);
	FOR(i,1,n) s[i]=(str[i]=='?'?-1:str[i]-'0');
	f[0][9]=1;
	for(int i=0;i+2<=n;i+=2) FOR(j,0,15){
		if (s[i+1]!=1 && s[i+2]!=1) qmo(f[i+2][to[j][0][0]]+=f[i][j]-mod);
		if (s[i+1]!=0 && s[i+2]!=1) qmo(f[i+2][to[j][1][0]]+=f[i][j]-mod);
		if (s[i+1]!=1 && s[i+2]!=0) qmo(f[i+2][to[j][0][1]]+=f[i][j]-mod);
		if (s[i+1]!=0 && s[i+2]!=0) qmo(f[i+2][to[j][1][1]]+=f[i][j]-mod);
	}
	int ans=0;
	FOR(i,0,15){
		if (s[n]!=1 && ((i>>2)&1)) qmo(ans+=f[n-1][i]-mod);
		if (s[n]!=0 && ((i>>3)&1)) qmo(ans+=f[n-1][i]-mod);
	}
	printf("%d\n",ans);
	MEM(f,0);
}
int main(){
	int T=read();
	while(T--) solve();
}
posted @ 2020-08-11 22:43  chdy  阅读(258)  评论(3编辑  收藏  举报