Topcoder SRM 616 Div2 1000 TwoLLogo

Task:
给定一个 nm 的平面图,由’.’与’#’构成,现要在’.’处画出两个 L 形图案,要求两个L不能相交,求方案数,答案对 P 取模。(n<=1000,P=1000000007)
Solution:
一个 L 由四个数字坐标决定,因此最朴素的做法即是枚举两个L,复杂度为 O(n8) ,期望得分为30分。

bool judge(int x1,int y1,int l1,int r1,int x,int y){
    if(x==l1){
        if(y>=y1&&y<=r1)return true;
    }
    if(y==y1){
        if(x>=x1&&x<=l1)return true;
    }
    return false;
}
struct P30{
    void solve(){
        ll ans=0;
        for(int x1=1;x1<=n;x1++)
            for(int y1=1;y1<=m;y1++){
                if(str[x1][y1]=='#')continue;
                for(int l1=x1+1;l1<=n;l1++){
                    if(str[l1][y1]=='#')break;
                    for(int r1=y1+1;r1<=m;r1++){
                        if(str[l1][r1]=='#')break;
                        for(int x2=1;x2<=n;x2++)
                            for(int y2=1;y2<=m;y2++){
                                if(str[x2][y2]=='#'||judge(x1,y1,l1,r1,x2,y2))continue;
                                for(int l2=x2+1;l2<=n;l2++){
                                    if(str[l2][y2]=='#'||judge(x1,y1,l1,r1,l2,y2))break;
                                    for(int r2=y2+1;r2<=m;r2++){
                                        if(str[l2][r2]=='#'||judge(x1,y1,l1,r1,l2,r2))break;
                                        ans++;
                                    }
                                }
                            }
                    }
                }
            }
        cout<<(ans/2)%P<<endl;
    }
}P30;

首先,显然在枚举的过程中,对于 L 的两条边的长度是不必要在循环内检验的,可以直接用O(n2)预处理出来。
定义 right[i][j] 表示从 (i,j) 点向右拓展能够拓展的长度, up[i][j] 表示从 (i,j) 点向上拓展能够拓展的长度。
因此我们枚举 L 的拐点坐标,会有以下三种情况:
情况
我们设第一个L的坐标为 (x1,y1) ,第二个为 (x2,y2)

  • 对于第一种,只有标红的线段是限定的,其余线段无关,因此
    tot=up[x1][y1]right[x1][y1]right[x2][y1]min(up[x2][y1],x2x11);
  • 对于第二种,所有线段都无限制,因此
    tot=up[x1][y1]up[x2][y2]right[x1][y1]right[x2][y2]
  • 对于第三种,第一个 L 向上的与第二个L向右的无关,而交点虚线部分的处理就比较麻烦了。我们可以分情况讨论:
    • 交点处给第一个 L tot=right[x1][y1]min(up[x2][y2],x2x11)
    • 交点处给第二个 L ,第二个L向上的边在红色段已经在前一种方案的统计中算过,因此: tot=(up[x2][y2]min(up[x2][y2],x2x11))min(right[x1][y1],y2y11)

于是就写出了 O(n4) 的代码,期望得分80分。

void Init(){
    for(int j=1;j<=m;j++)
        for(int i=1;i<=n;i++){
            if(str[i][j]=='#')continue;
            if(i==1||str[i-1][j]=='#')up[i][j]=0;
            else up[i][j]=up[i-1][j]+1;
        }
    for(int i=1;i<=n;i++)
        for(int j=m;j>=1;j--){
            if(str[i][j]=='#')continue;
            if(j==m||str[i][j+1]=='#')right[i][j]=0;
            else right[i][j]=right[i][j+1]+1;
        }
}
struct P80{
    ll calc(int x1,int y1,int x2,int y2){//y1<y2
        if(x1==x2)return 1LL*Up[x1][y1]*Up[x2][y2]*min(Right[x1][y1],y2-y1-1)*Right[x2][y2];
        if(x1>x2)return 1LL*Up[x1][y1]*Up[x2][y2]*Right[x1][y1]*Right[x2][y2];
        else{
            int t=min(Up[x2][y2],x2-x1-1);
            return 1LL*Up[x1][y1]*Right[x2][y2]*(1LL*Right[x1][y1]*t+1LL*(Up[x2][y2]-t)*min(Right[x1][y1],y2-y1-1));
        }
    }
    void solve(){
        ll ans=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                if(str[i][j]=='#')continue;
                for(int k=j+1;k<=m;k++)
                    if(str[i][k]=='#')break;
                    else Right[i][j]++;
            }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                if(str[i][j]=='#')continue;
                for(int k=i-1;k>=1;k--)
                    if(str[k][j]=='#')break;
                    else Up[i][j]++;
            }
        for(int y1=1;y1<=m;y1++)
            for(int x1=1;x1<=n;x1++){
                if(str[x1][y1]=='#')continue;
                //y2==y1 judge
                for(int x2=x1+1;x2<=n;x2++){
                    if(str[x2][y1]=='#')continue;
                    ans+=1LL*Up[x1][y1]*Right[x1][y1]*Right[x2][y1]*min(Up[x2][y1],x2-x1-1);
                }
                for(int y2=y1+1;y2<=m;y2++)
                    for(int x2=1;x2<=n;x2++){
                        if(str[x2][y2]=='#')continue;
                        ans+=calc(x1,y1,x2,y2);
                    }
            }
        cout<<ans%P<<endl;
    }
}P80;

其实标程的复杂度就是 O(n4) ,然而 KyleYoung 大神写出了 O(n2) 的解法…Orz
凭借“正难则反”的指导思想,我们可以先算出总方案数,再减去不符合的方案数。
同样的,对于不符合的方案数,也是三种情况。我们可以选择一个特殊点来枚举,即图中两个 L 的交叉点。设此点坐标为(x,y)
首先我们与处理出 left 数组与 down 数组。 left[i][j] 表示 (i,j) 左边各点向上延伸的方案数之和, down[i][j] 表示 (i,j) 下边向右延伸的方案数之和。

left[i][j]=left[i][j1]+up[i][j1]
down[i][j]=down[i+1][j]+right[i+1][j]

情况
- 对于第一种,第一个 L 的右边范围为与第二个L的向上延伸范围为红色区域,其余线段无关: tot=(up[i][j]+1)down[i][j](right[i][j]+1)left[i][j]
- 对于第二种: tot=right[i][j]up[i][j]left[i][j](right[i][j]+1)
- 对于第三种: tot=right[i][j]up[i][j]down[i][j](up[i][j]+1)
于是就解决了这道题,复杂度 O(n2)

#include<stdio.h>
#define P 1000000007
#define M 1005
char str[M][M];
int up[M][M],down[M][M],left[M][M],right[M][M];
int n,m;
void Init(){
    for(int j=1;j<=m;j++)
        for(int i=1;i<=n;i++){
            if(str[i][j]=='#')continue;
            if(i==1||str[i-1][j]=='#')up[i][j]=0;
            else up[i][j]=up[i-1][j]+1;
        }
    for(int i=1;i<=n;i++)
        for(int j=m;j>=1;j--){
            if(str[i][j]=='#')continue;
            if(j==m||str[i][j+1]=='#')right[i][j]=0;
            else right[i][j]=right[i][j+1]+1;
        }
    for(int i=1;i<=n;i++)
        for(int j=2;j<=m;j++)
            if(str[i][j]!='#')left[i][j]=left[i][j-1]+up[i][j-1];
    for(int j=1;j<=m;j++)
        for(int i=n-1;i>=2;i--)
            if(str[i][j]!='#')down[i][j]=down[i+1][j]+right[i+1][j];
}
int total(){
    int sum=0,res=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(str[i][j]!='#'){
                int t=1LL*up[i][j]*right[i][j]%P;
                res=(res+1LL*t*sum)%P;
                sum=(sum+t)%P;
            }
    return res;
}
int calc1(){
    int res=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(str[i][j]!='#')res=(res+1LL*(up[i][j]+1)*down[i][j]%P*(right[i][j]+1)%P*left[i][j]%P)%P;
    return res;
}
int calc2(){
    int res=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)//横向 
            if(str[i][j]!='#')
                res=(res+1LL*right[i][j]*up[i][j]%P*left[i][j]%P*(right[i][j]+1)%P)%P;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)//竖直 
            if(str[i][j]!='#')res=(res+1LL*right[i][j]*up[i][j]%P*down[i][j]%P*(up[i][j]+1)%P)%P;
    return res;
}
int doit(int x){
    return (x%P+P)%P;
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%s",str[i]+1);
    Init();
    printf("%d\n",doit(doit(total()-calc1())-calc2()));
    return 0;
}
内容概要:该论文聚焦于6G通信中20-100GHz频段的电磁场(EMF)暴露评估问题,提出了一种基于自适应可重构架构神经网络(RAWA-NN)的预测框架。该框架通过集成权重分析模块和优化模块,能够自动优化网络超参数,显著减少训练时间。模型使用70%的前臂数据进行训练,其余数据用于测试,并用腹部和股四头肌数据验证模型泛化能力。结果显示,该模型在不同参数下的相对差异(RD)在前臂低于2.6%,其他身体部位低于9.5%,可有效预测皮肤表面的温升和吸收功率密度(APD)。此外,论文还提供了详细的代码实现,涵盖数据预处理、权重分析模块、自适应优化模块、RAWA-NN模型构建及训练评估等内容。 适合人群:从事电磁兼容性研究、6G通信技术研发以及对神经网络优化感兴趣的科研人员和工程师。 使用场景及目标:①研究6G通信中高频段电磁暴露对人体的影响;②开发更高效的电磁暴露评估工具;③优化神经网络架构以提高模型训练效率和预测精度。 其他说明:论文不仅提出了理论框架,还提供了完整的代码实现,方便读者复现实验结果。此外,论文还讨论了未来的研究方向,包括扩展到更高频段(如300GHz)的数据处理、引入强化学习优化超参数、以及实现多物理场耦合的智能电磁暴露评估系统。建议读者在实际应用中根据具体需求调整模型架构和参数,并结合真实数据进行验证。
内容概要:本文是北京金融科技产业联盟发布的《基于数据空间的金融数据可信流通研究报告》,探讨了金融数据可信流通的现状、挑战和发展前景。文章首先介绍了金融数据在数字化转型中的重要性及其面临的隐私保护和安全挑战。接着,文章详细阐述了数据空间的概念及其发展历程,尤其是可信数据空间(TDM)在我国的发展情况。文中还深入分析了金融数据可信流通的典型应用场景、关键技术和方案架构,如数据访问控制、数据使用控制、智能合约、数据脱敏等。最后,文章展示了多个典型场景应用案例,如中信银行总分行数据流通管控、工银金租数据流通、银联安全生物特征支付等,并总结了当前可信数据空间建设中存在的法规、技术、标准和商业模式挑战,提出了相应的政策建议。 适用人群:金融行业从业者、数据安全管理人员、政策制定者、科技研发人员等。 使用场景及目标:①理解金融数据可信流通的重要性和挑战;②学习可信数据空间的关键技术和应用场景;③探索金融数据可信流通的具体实践案例;④了解当前可信数据空间建设的瓶颈和未来发展方向。 其他说明:本文不仅提供了详尽的技术和应用分析,还提出了具体的政策建议,有助于推动金融数据可信流通的健康发展。阅读本文可以帮助读者深入了解金融数据安全保护和高效利用的最佳实践,为相关政策和技术的发展提供参考。
基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业),个人经导师指导并认可通过的高分设计项目,评审分99分,代码完整确保可以运行,小白也可以亲自搞定,主要针对计算机相关专业的正在做大作业的学生和需要项目实战练习的学习者,可作为毕业设计、课程设计、期末大作业,代码资料完整,下载可用。 基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值