But my words, like si|

MessageBoxA

园龄:4年10个月粉丝:4关注:0

NOI模拟 UTF-8

涉及知识点:数位DP

前言

其实这题也没啥好写的,就是好久没做大模拟调代码把人调废了,警醒一下自己……

题意

大模拟,不给简化题意了

n105

思路

大递推 DP 里面套小数位 DP,挺恶心的。

fi 为以第 i 字节结尾的方案数,每次考虑用 4 个字节存并且是以 i 结尾的数,然后 3 个字节、2 个字节……判断合法然后转移即可。

代码

用了个 class 来维护,比复制粘贴四次记搜好看多了。

#include<bits/stdc++.h>
#define add(a,b) a=((a)+(b))%P
#define checkch(x,c) (s[id][x]==c || s[id][x]=='?')
using namespace std;
typedef long long LL;
const LL P=1e9+7;
const int MAXN=1e5+5,FOLLOW=1,HEAD1=2,HEAD2=4,HEAD3=8,HEAD4=16;
int n,type[MAXN];
string s[MAXN];
LL ans=0,f[MAXN];
inline int checktype(const int& id){
    int res=0;
    if(checkch(0,'1') && checkch(1,'0')) res|=FOLLOW;
    if(checkch(0,'0')) res|=HEAD1;
    if(checkch(0,'1') && checkch(1,'1') && checkch(2,'0')) res|=HEAD2;
    if(checkch(0,'1') && checkch(1,'1') && checkch(2,'1') && checkch(3,'0')) res|=HEAD3;
    if(checkch(0,'1') && checkch(1,'1') && checkch(2,'1') && checkch(3,'1') && checkch(4,'0')) res|=HEAD4;
    if(!res){
        // cout<<s[id]<<endl;
        cout<<0<<endl;
        exit(0);
    }
    return res;
}
class DigitDP{
    private:
        int len;
        LL g[20][2][2];
        string str,lstr,rstr;
    public:
        DigitDP(int _len,string _lstr,string _rstr){
            len=_len;
            lstr=_lstr;
            rstr=_rstr;
        }
        inline void reset(string _str){
            memset(g,-1,sizeof(g));
            str=_str;
        }
        LL dfs(int dep=0,bool liml=true,bool limr=true){
            if(g[dep][liml][limr]!=-1) return g[dep][liml][limr];
            if(dep>=len){
                return g[dep][liml][limr]=1;
            }
            LL res=0;
            if(str[dep]=='?'){
                for(int dig=(liml?(lstr[dep]-'0'):0);dig<=(limr?(rstr[dep]-'0'):1);dig++){
                    add(res,dfs(dep+1,liml&&(dig==lstr[dep]-'0'),limr&&(dig==rstr[dep]-'0')));
                }
            }
            else if(str[dep]=='1'){
                if((!limr) || (rstr[dep]=='1'))
                    add(res,dfs(dep+1,liml&&('1'==lstr[dep]),limr&&('1'==rstr[dep])));
            }
            else{
                if((!liml) || (lstr[dep]=='0'))
                    add(res,dfs(dep+1,liml&&('0'==lstr[dep]),limr&&('0'==rstr[dep])));
            }
            return g[dep][liml][limr]=res;
        }
}
dp8 (8, "00000001","11111111"),
dp11(11,"00010000000","11111111111"),
dp16(16,"0000100000000000","1111111111111111"),
dp18(18,"010000000000000000","110001001101001111");
int main(){
    // freopen("utf.in","r",stdin);
    // freopen("utf.out","w",stdout);

    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>s[i];
        type[i]=checktype(i);
        // cout<<i<<' ';
        // if(type[i]&FOLLOW) cout<<"FOLLOW"<<' ';
        // if(type[i]&HEAD1) cout<<"HEAD1"<<' ';
        // if(type[i]&HEAD2) cout<<"HEAD2"<<' ';
        // if(type[i]&HEAD3) cout<<"HEAD3"<<' ';
        // if(type[i]&HEAD4) cout<<"HEAD4"<<' ';
        // cout<<endl;
    }
    f[0]=1;
    for(int i=1;i<=n;i++){
        if(i>=1 && (type[i]&HEAD1)){
            string tmp;
            for(int j=1;j<=7;j++) tmp+=s[i][j];
            dp8.reset(tmp);
            add(f[i],f[i-1]*dp8.dfs()%P);
        }
        if(i>=2 && (type[i-1]&HEAD2) && (type[i]&FOLLOW)){
            string tmp;
            for(int j=3;j<=7;j++) tmp+=s[i-1][j];
            for(int j=2;j<=7;j++) tmp+=s[i][j];
            dp11.reset(tmp);
            add(f[i],f[i-2]*dp11.dfs()%P);
        }
        if(i>=3 && (type[i-2]&HEAD3) && (type[i-1]&FOLLOW) && (type[i]&FOLLOW)){
            string tmp;
            for(int j=4;j<=7;j++) tmp+=s[i-2][j];
            for(int j=2;j<=7;j++) tmp+=s[i-1][j];
            for(int j=2;j<=7;j++) tmp+=s[i][j];
            dp16.reset(tmp);
            add(f[i],f[i-3]*dp16.dfs()%P);
        }
        if(i>=4 && (type[i-3]&HEAD4) && (type[i-2]&FOLLOW) && (type[i-1]&FOLLOW) && (type[i]&FOLLOW)){
            bool flag=1;
            for(int j=5;j<=7 && flag;j++)// 四个字节的情况虽然只有后18位有效,但是还是需要判断第一个字节的后三位是否为0
                if(s[i-3][j]=='1') flag=0;
            if(flag){
                string tmp;
                for(int j=2;j<=7;j++) tmp+=s[i-2][j];
                for(int j=2;j<=7;j++) tmp+=s[i-1][j];
                for(int j=2;j<=7;j++) tmp+=s[i][j];
                dp18.reset(tmp);
                add(f[i],f[i-4]*dp18.dfs()%P);
            }
        }
    }
    cout<<f[n]<<endl;
    return 0;
}

本文作者:MessageBoxA

本文链接:https://www.cnblogs.com/SkyNet-PKN/p/18218221

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   MessageBoxA  阅读(6)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 evening Corn Wave
  2. 2 Группа крови Кино
  3. 3 The Sound Of Silence Simon & Garfunkel
  4. 4 dB doll YUE.STEVEN
Группа крови - Кино
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.