欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[THUPC2018]蛋糕solution

程序员文章站 2022-06-16 20:50:32
...

题目描述

最近,菲菲学会了做蛋糕,她做了一个4D的蛋糕送给牛牛,这个蛋糕的大小是:a×b×c×da \times b \times c \times d

蛋糕所有的表面都抹着奶油,牛牛想把蛋糕沿着与表面平行的超平面,切成1×1×1×11 \times 1 \times 1 \times 1的小块。

现在,牛牛想知道,在这些小块蛋糕中,有00个、11个、22\cdots\cdots88个表面抹着奶油的有分别有多少块。

题目大意

一个a×b×c×da\times b\times c\times d4D图形,对每个表面染色,问被染00面、11面、228\cdots\cdots 8面的块分别有几个。

解题思路

第①​种解法

考虑当前第ii维,最上面和最下面22i1i-1维的图形会减少11个被染色的面。 剩下li2l_i-2个图形会减少22个被染色的面。

[THUPC2018]蛋糕solution

这幅图中,维度ii33,假设图形1,21,222维图形,那么图形11的下面被覆盖,减少了11个被染色的面。 图形22的上下面都被覆盖,减少了22个被染色的面。

算法是DFSDFS,从第44维一直到第00维计算答案。

当构成图形的某个长lil_i11时需进行特判,这时增加的个数应该是i1i-1维时的个数,因为1×x=x1\times x=x,相当于i1i-1维。

代码实现

#include<bits/stdc++.h>
typedef long long ll;//防止计算溢出
int T,l[10];
ll a[10];
#define p 2148473648//原题中要对2148473648取模
void dfs(int t,ll s,int m){//t表示当前维度,s表示对m面染色能增加的个数,m表示当前计算的染色面数
    if(!t)return void((a[m]+=s)%=p);//当t为0维度,增加答案
    if(l[t]==1)return dfs(t-1,s,m);//特判长度为1时增加的个数
    dfs(t-1,s*2%p,m-1);//第i维的最上最下2个i-1维的图形
    dfs(t-1,s*(l[t]-2)%p,m-2);//第i维中间的l-2个图形
}
int main(){
    for(scanf("%d",&T);T--;){
        scanf("%d%d%d%d",&l[1],&l[2],&l[3],&l[4]),dfs(4,1,8);//从第4维倒推
        for(int i=0;i<=8;i++)printf("%lld%c",a[i],i==8?'\n':' '),a[i]=0;
    }
    return 0;
}

第②种解法

推导过程

由于注意到本题只有44维,数据不大,可以手玩推公式。

直接44维计算较难理解,所以先推一下小学就学过的33维染色个数的公式。

题目为:有一个由1×1×11\times 1\times 1的小立方体构成的a×b×ca\times b\times c的大立方体,给这个大立方体的表面涂上颜色,求被涂了0,1,2,3,40,1,2,3,4面的小立方体各有多少个。

  • Ⅰ.考虑a,b,c2a,b,c\geq 2的情况(三维图形中00个维度为11),所以不存在被涂了44面的小正方体,用ansians_i表示被涂了ii面的小立方体数量,那么规律为:
    ans0=(a2)×(b2)×(c2)ans1=2×((a2)×(b2)+(a2)×(c2)+(b2)×(c2))ans2=4×((a2)×(b2)×(c2))ans3=8ansx=0 (x>3) ans_0=(a-2)\times(b-2)\times(c-2)\\ ans_1=2\times((a-2)\times(b-2)+(a-2)\times(c-2)+(b-2)\times(c-2))\\ ans_2=4\times((a-2)\times(b-2)\times(c-2))\\ ans_3=8\\ ans_x=0\ (x>3)

  • Ⅱ.如果a,b,ca,b,c中假设c=1c=1(三维图形中11个维度为11),那么规律为:
    ans0=ans1=0ans2=(a2)×(b2)ans3=2×(a+b4)ans4=4ansx=0 (x>4) ans_0=ans_1=0\\ans_2=(a-2)\times(b-2)\\ans_3=2\times(a+b-4)\\ans_4=4\\ ans_x=0\ (x>4)

  • Ⅲ.如果a,b,ca,b,c中假设b,c=1b,c=1(三维图形中22个维度为11),那么规律为:
    ans0=ans1=ans2=ans3=0ans4=a2ans5=2ansx=0 (x>5) ans_0=ans_1=ans_2=ans_3=0\\ans_4=a-2\\ans_5=2\\ans_x=0\ (x>5)

  • Ⅳ.如果a,b,c=1a,b,c=1(三维图形中33个维度为11),那么规律为:
    ans0=ans1=ans2=ans3=ans4=ans5=0ans6=1ansx=0 (x>6) ans_0=ans_1=ans_2=ans_3=ans_4=ans_5=0\\ans_6=1\\ans_x=0\ (x>6)

以上推出了三维物体的全部规律。

然后我们考虑四维,按照有0,1,2,3,40,1,2,3,4个维度为11来分类讨论。

方便计算,先definedefine

#define A (a-2)%mod
#define B (b-2)%mod
#define C (c-2)%mod
#define D (d-2)%mod

Ⅰ.四维物体有00个维度为11

ans[0]=A*B*C*D;
ans[1]=2*(A*B*C+A*B*D+A*C*D+B*C*D)%mod;
ans[2]=4*(A*B+A*C+A*D+B*C+B*D+C*D)%mod;
ans[3]=8*(A+B+C+D)%mod;
ans[4]=16;

Ⅱ.四维物体有11个维度为11,相当于三维物体有11个维度为11,那么可以进行规律转换,只不过要注意, ansians_i的下标要加上2 ,因为我们增加了一维。

ans[2]=A*B*C%mod;
ans[3]=2*(A*B+A*C+B*C)%mod;
ans[4]=4*(A+B+C)%mod;
ans[5]=8;

Ⅲ.四维物体有22个维度为11,相当于三维物体有11个维度为11

ans[4]=(a-2)*(b-2)%mod;
ans[5]=2*(a+b-4)%mod;
ans[6]=4;

Ⅳ.四维物体有33个维度为11,相当于三维物体有22个维度为11

ans[6]=(a%mod-2%mod)%mod;
ans[7]=2;

Ⅴ.四维物体有44个维度为11,相当于三维物体有33个维度为11

ans[8]=1;

到这里,四维图形的公式就推导完了。

代码实现

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int mod=2148473648;
#define A (a-2)%mod
#define B (b-2)%mod
#define C (c-2)%mod
#define D (d-2)%mod
int ans[9],a,b,c,d,cnt,f[5];
signed main(){
    int T;
    scanf("%lld",&T);
    while(T--){
        memset(ans,0,sizeof ans);
        memset(f,0,sizeof f);
        cnt=0;
        scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
        if(a!=1)f[++cnt]=a;
        if(b!=1)f[++cnt]=b;
        if(c!=1)f[++cnt]=c;
        if(d!=1)f[++cnt]=d;
        if(cnt==4){
            ans[0]=A*B*C*D;
            ans[1]=2*(A*B*C+A*B*D+A*C*D+B*C*D)%mod;
            ans[2]=4*(A*B+A*C+A*D+B*C+B*D+C*D)%mod;
            ans[3]=8*(A+B+C+D)%mod;
            ans[4]=16;
            for(int i=0;i<=8;i++)printf("%lld ",ans[i]);     
        }
        if(cnt==3){
            a=f[1],b=f[2],c=f[3];
            ans[2]=A*B*C%mod;
            ans[3]=2*(A*B+A*C+B*C)%mod;
            ans[4]=4*(A+B+C)%mod;
            ans[5]=8;
            for(int i=0;i<=8;i++)printf("%lld ",ans[i]);
        }
        if(cnt==2){
            a=f[1],b=f[2];
            ans[4]=(a-2)*(b-2)%mod;
            ans[5]=2*(a+b-4)%mod;
            ans[6]=4;
            for(int i=0;i<=8;i++)printf("%lld ",ans[i]);       
        }
        if(cnt==1){
            a=f[1];
            ans[6]=(a%mod-2%mod)%mod;
            ans[7]=2;
            for(int i=0;i<=8;i++)printf("%lld ",ans[i]);
        }
        if(cnt==0){
            ans[8]=1;
            for(int i=0;i<=8;i++)printf("%lld ",ans[i]);
        }
        printf("\n");
    }
    return 0;
}