0x5C~0x5D

0x5C~0x5D

0x5C 计数类DP

a.[√] Gerald and Giant Chess

题目传送

sol:

发现格子数很大,但是黑色格子数很小,所以考虑往黑色格子上靠。

所以考虑到容斥一下,即 不经过黑格子的路径条数=路径总条数-至少经过一个黑格子的路径条数。

从点\((1,1)\)到点\((x,y)\)的路径总条数应该为\(C_{x+y-2}^{x-1}\) ,只需求经过了黑格子的路径条数。

容易想到对把这些黑格子拿出来,同时按照距离点\((1,1)\)的远近(或按行列)排序,转为序列问题。

\(f[i]\)表示不经过其他黑格子,从\((1,1)\)(序列上)第i个黑格子\((x_i,y_i)\)的路径条数。

转移应该为:
\[ f[i]=C_{x_i+y_i-2}^{x_i-1}-\sum_{j=0}^{i-1}f[j]*C_{x_i+y_i-x_j+y_j}^{x_i-y_i}\ \ (x_i≥x_j\ , \ y_i≥y_j) \]
注意到答案实际上即为\(f[n+1]\)

code:

#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define IL inline
#define LL long long
#define DB double
using namespace std;

IL int gi() {
   RG int x=0,w=0; char ch=getchar();
   while (ch<'0'||ch>'9') {if (ch=='-') w=1;ch=getchar();}
   while (ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
   return w?-x:x;
}

const int N=2003;
const int M=2e5+3;
const int mod=1e9+7;

int h,w,n,fc[M],fcn[M];
LL f[N];

struct Black{int x,y;}b[N];
IL bool cmp(Black A,Black B) {return A.x+A.y<B.x+B.y;}

IL int qpow(int x,int p) {
    RG int ans=1;
    for(;p;p>>=1,x=1ll*x*x%mod)
        if(p&1) ans=1ll*ans*x%mod;
    return ans;
}

IL int C(int a,int b) {return 1ll*fc[a]*fcn[b]%mod*fcn[a-b]%mod;}

int main()
{
    RG int i,j;
    h=gi(),w=gi(),n=gi();
    for(i=1;i<=n;++i) b[i].x=gi(),b[i].y=gi();
    b[0]=(Black){1,1},b[n+1]=(Black){h,w};
    sort(b+1,b+n+2,cmp);
    fc[0]=fcn[0]=1;
    for(i=1;i<=h+w;++i)
        fc[i]=1ll*fc[i-1]*i%mod,fcn[i]=qpow(fc[i],mod-2);
    for(i=1;i<=n+1;++i) {
        RG LL tmp=0;
        RG int now=b[i].x+b[i].y;
        for(j=1;j<i;++j)
            if(b[i].x>=b[j].x&&b[i].y>=b[j].y)
                tmp=(tmp+1ll*f[j]*C(now-b[j].x-b[j].y,b[i].x-b[j].x)%mod)%mod;
        f[i]=((C(b[i].x+b[i].y-2,b[i].x-1)-tmp)%mod+mod)%mod;                        
    }
    printf("%lld\n",f[n+1]);
    return 0;
}
b.[√] Connected Graph

题目传送

sol:

吐槽:E心的高精!!!code交poj上SE(System Error)什么鬼,,,

进入正题,

同上面的那一个题,连通无向图数=图总数-不连通无向图数。

x个点的图的总数显然为\(2^{(\frac {x*(x-1)}{2})}\)

假设现在已经求出了i-1个点构成的连通无向图数,记为\(f[i-1]\)

现在考虑i个点构成的图的生成,只需考虑不连通的无向图数。

可以这样考虑,整个图可以分为一个连通块(A)+若干连通块(B)。

只要保证A部分和B部分之间没有连边就好了。

所以考虑维护A,让A部分逐渐变化,可以保证不重不漏。

用f表示出来,则\(f[i]\)的求法应该为:
\[ f[i]=2^{(\frac {i*(i-1)}{2})}-\sum_{j=1}^{i-1}f[j]*C_{i-1}^{j-1}*2^{(\frac {(i-j)*(i-j-1)}{2})} \]

code(不是我自己的(╯▽╰)):

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct Int {
    int a[800],len;
    Int(int x=0) {
        len=0;
        memset(a,0,sizeof(a));
        do {
            a[++len]=x%10;
            x/=10;
        }while(x);
    }
    inline void update(int n) {
        int k;
        for(k=1;k<=n||a[k];++k)
            if(a[k]>=10) a[k+1]+=a[k]/10,a[k]%=10;
        len=max(k-1,1);
        while(!a[len]&&len>1)--len;
    }
    int& operator [](int x){return a[x];}
    const int& operator [](int x)const{return a[x];}
    inline void print() {
        for(register int i=len;i;--i)printf("%d",a[i]);
        printf("\n");
    }
};
inline Int operator +(const Int& a,const Int& b) { 
    Int ans;int n=max(a.len,b.len);
    for(register int i=1;i<=n;++i) ans[i]+=a[i]+b[i];
    ans.update(n);
    return ans;
}
inline Int operator -(const Int& a,const Int& b) {
    Int ans;int n=max(a.len,b.len);
    for(register int i=1;i<=n;++i) {
        ans[i]+=a[i]-b[i];
        if(ans[i]<0) ans[i]+=10,--ans[i+1];
    }
    ans.update(n);
    return ans;
}
inline Int operator *(const Int& a,const Int& b) {
    Int ans;
    for(register int i=1;i<=a.len;++i)
        for(register int j=1;j<=b.len;++j)
            ans[i+j-1]+=a[i]*b[j];
    ans.update(a.len+b.len-1);
    return ans;
}
Int f[51],c[51][51],qua[51*51];
inline void init() {
    c[0][0]=Int(1);
    for(register int i=1;i<=50;++i) {
        c[i][0]=Int(1);
        for(register int j=1;j<=i;++j)
            c[i][j]=c[i-1][j-1]+c[i-1][j];
    }
    qua[0]=Int(1);Int base(2);
    for(register int i=1;i<=50*50;++i)qua[i]=qua[i-1]*base;
    f[1]=Int(1);
    for(register int i=2;i<=50;++i) {
        f[i]=qua[i*(i-1)/2];
        for(register int j=1;j<i;++j)f[i]=f[i]-f[j]*c[i-1][j-1]*qua[(i-j)*(i-j-1)/2];
    }
}
int main()
{
    init();int x;
    while(~scanf("%d",&x)&&x)f[x].print();
    return 0;
}
c.[√] A decorative fence

题目传送

sol:

考虑一块一块板子的补,都从左边补上。

假设当前是第i块板子,在已放的板子中从小到大排第j大,记为\(f[i,j,0/1]\)

注意上述放板子不一定顺序取,i不是代表的前i块板子(当然事实上二者等价),0/1代表低(高)位。

那么转移应该为:
\[ f[i,j,0]=\sum_{k=j}^{i-1}f[i-1,k,1]\\ f[i,j,1]=\sum_{k=1}^{j-1}f[i-1,k,0] \]
DP完成后,考虑把答案拼凑出来。

可以发现第一块板子需单独考虑,剩下的板子的选择都会受之前的板子的影响。

记录一下用过的板子,上一块板子,和当前的状态(高低位)模拟即可。

code:

#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define IL inline
#define LL long long
#define DB double
using namespace std;

const int N=23;

LL m,f[N][N][2];
int n,last,state,use[N];

IL void DP() {
    RG int i,j,k;
    f[1][1][0]=f[1][1][1]=1;
    for(i=2;i<=20;++i) 
        for(j=1;j<=i;++j) {
            for(k=j;k<i;++k) f[i][j][0]+=f[i-1][k][1];
            for(k=1;k<j;++k) f[i][j][1]+=f[i-1][k][0];
        }
}

int main()
{
    RG int i,j,k,T;
    for(DP(),scanf("%d",&T);T;--T) {
        scanf("%d%lld",&n,&m);
        memset(use,0,sizeof(use));
        for(i=1;i<=n;++i) {
            if(f[n][i][1]>=m) {
                last=i,state=1;
                break;
            }
            m-=f[n][i][1];
            if(f[n][i][0]>=m) {
                last=i,state=0;
                break;
            }
            m-=f[n][i][0];
        }
        use[last]=1;
        printf("%d ",last);
        for(i=2;i<=n;++i) {
            state^=1;
            for(j=1,k=0;j<=n;++j) {
                if(use[j]) continue;
                ++k;
                if(!state&&last>j||state&&j>last)
                    if(f[n-i+1][k][state]>=m) {last=j;break;}
                    else m-=f[n-i+1][k][state];
            }
            use[last]=1;
            printf("%d ",last);
        }
        putchar('\n');
    }
    return 0;
}

0x5D 数位统计DP

d.[√] Apocalypse Someday

题目传送

sol:

容易考虑到设\(g[i]\)表示由i位构成的魔鬼数个数,\(f[i,0/1/2]\)表示i位构成的末尾又连续的0/1/2个6的非魔鬼数个数。

那么考虑每次从末尾填一个新的数,则转移应该为:
\[ f[i,2]=f[i-1,0],f[i,1]=f[i-1,0]\\ f[i,0]=9*(f[i-1,0]+f[i-1,1]+f[i-1,2])\\ g[i]=f[i-1,2]+g[i-1]*10 \]
和上面的题目类似,考虑把答案拼凑出来。

注意,由g的转移方式可知,g中的方案数包括含有前导0的。

首先利用g确定位数。

然后从低位到高位依次填数,枚举当前位填的数,

然后计算出填了它之后能有多少个魔鬼数(还需特别考虑已经是魔鬼数和当前填了6的情况,详见代码)。

如果小于总数,则当前为应该填一个更大的,否则就填它。

code:

#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define IL inline
#define LL long long
#define DB double
using namespace std;

IL int gi() {
   RG int x=0,w=0; char ch=getchar();
   while (ch<'0'||ch>'9') {if (ch=='-') w=1;ch=getchar();}
   while (ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
   return w?-x:x;
}

const int N=17;

int n,m,ans[N];
LL g[N],f[N][3];

IL void DP() {
    RG int i;
    f[0][0]=1,f[1][0]=9,f[1][1]=1;
    for(i=2;i<=15;++i) {
        g[i]=f[i-1][2]+10*g[i-1];
        f[i][2]=f[i-1][1],f[i][1]=f[i-1][0];
        f[i][0]=9*(f[i-1][2]+f[i-1][1]+f[i-1][0]);
    }
}

int main()
{
    RG int i,j,k,p,T;
    for(DP(),T=gi();T;--T) {
        n=gi();
        for(m=3;g[m]<n;++m);
        for(i=m,k=0;i;--i) {
          //k用于记录末尾已经有几个连续的6,k=3代表已经是魔鬼数。
            for(j=0;j<=9;++j) {
                RG LL cnt=g[i-1];
                if(j==6||k==3)
                    for(p=max(3-k-(j==6),0);p<=2;++p) cnt+=f[i-1][p];
                if(cnt<n) n-=cnt;
                else {
                    if(k<3) k=(j==6)?k+1:0;
                    printf("%d",j);
                    break;
                }
            }
        }
        putchar('\n');
    }
    return 0;
}

f.[√] 同类分布

题目传送

sol:

首先考虑需要记录的东西,记\(pos\)表示填到的位数,\(sum\)表示各位之和,\(res\)表示填出来数的数值。

如果存在\(sum|res\)那么就可以贡献1的答案。

但是发现\(res\)过于大,无法实现直接记录,那么考虑取模。

可以发现最好的模数就是\(sum\)本身了。

故此时若存在\(res==0\&\&sum==mod\)即可贡献1的答案。

然后发现\(mod\)\(sum\)是不断变化的,所以考虑到枚举所有的\(mod\in[1,len*9]\)\(len\)为上界数的长度。

最后用记忆化搜索的方式实现即可。

注意当前位数的取值范围有可能被上一位限制了,不一定为\([0,9]\)

code:

#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define IL inline
#define LL long long
#define DB double
using namespace std;

int mod,len,a[23];
LL l,r,f[23][203][203];

LL dfs(int pos,int sum,int res,int lim) {
    if(pos>len) return sum==mod&&!res?1:0;
    if(!lim&&f[pos][sum][res]!=-1) return f[pos][sum][res];
    RG LL ans=0;
    RG int i,upl=lim?a[len-pos+1]:9;
    for(i=0;i<=upl;++i) 
        ans+=dfs(pos+1,sum+i,(10*res+i)%mod,lim&&i==upl);
    return lim?ans:f[pos][sum][res]=ans;
}

IL LL getans(LL x) {
    RG LL ans=0;
    for(len=0;x;x/=10) a[++len]=x%10;
    for(mod=1;mod<=len*9;++mod) {
        memset(f,-1,sizeof(f));
        ans+=dfs(1,0,0,1);
    }
    return ans;
}

int main()
{
    scanf("%lld%lld",&l,&r);
    printf("%lld\n",getans(r)-getans(l-1));
    return 0;
}

转载于:https://www.cnblogs.com/Bhllx/p/11015077.html

static const uint8_t _CRCLo[] = { 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 };
最新发布
06-09
int main() { unsigned int v19; const unsigned char sbox0[256] ={0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16}; const char* a3="UK*@3oKpFlVVnadsTfdA"; int v7=16; memcpy(&v19, a3, v7); for (int j = 0; j != 16; ++j ) *((_BYTE *)&v19 + j) = sbox0[*((unsigned *)&v19 + j)]; return 0; }输出v19值
06-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值