Topcoder SRM 616 Div2 1000 TwoLLogo
来源:互联网 发布:英雄无敌3恐怖骑士知乎 编辑:程序博客网 时间:2024/06/06 03:52
TwoLLogo
Task:
给定一个
Solution:
一个
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;
首先,显然在枚举的过程中,对于
定义
因此我们枚举
我们设第一个
- 对于第一种,只有标红的线段是限定的,其余线段无关,因此
tot=up[x1][y1]∗right[x1][y1]∗right[x2][y1]∗min(up[x2][y1],x2−x1−1); - 对于第二种,所有线段都无限制,因此
tot=up[x1][y1]∗up[x2][y2]∗right[x1][y1]∗right[x2][y2] - 对于第三种,第一个
L 向上的与第二个L 向右的无关,而交点虚线部分的处理就比较麻烦了。我们可以分情况讨论:- 交点处给第一个
L :tot=right[x1][y1]∗min(up[x2][y2],x2−x1−1) - 交点处给第二个
L ,第二个L 向上的边在红色段已经在前一种方案的统计中算过,因此:tot=(up[x2][y2]−min(up[x2][y2],x2−x1−1))∗min(right[x1][y1],y2−y1−1)
- 交点处给第一个
于是就写出了
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;
其实标程的复杂度就是
凭借“正难则反”的指导思想,我们可以先算出总方案数,再减去不符合的方案数。
同样的,对于不符合的方案数,也是三种情况。我们可以选择一个特殊点来枚举,即图中两个
首先我们与处理出
- 对于第一种,第一个
- 对于第二种:
- 对于第三种:
于是就解决了这道题,复杂度
#include<stdio.h>#define P 1000000007#define M 1005char 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;}
0 0
- Topcoder SRM 616 Div2 1000 TwoLLogo
- Topcoder SRM 635 div2 1000
- Topcoder SRM 636 div2 1000
- TopCoder SRM 634 Div2 Problem 1000 - SpecialStrings
- Topcoder SRM 640 Div2 1000(巧妙数学题)
- Topcoder SRM 517 DIV2 1000 CuttingGrass
- Topcoder SRM 566 DIV2 1000 FencingPenguinsEasy
- Topcoder SRM 549 DIV2 1000 OrderOfTheHats
- Topcoder SRM 561 DIV2 1000 FoxAndTouristFamilies
- topcoder SRM 513 DIV2
- TopCoder SRM 543 DIV2
- topcoder-srm-233-div2
- Topcoder SRM Div2 Level2
- TopCoder SRM 144 div2
- TOPCODER SRM 612 DIV2
- TOPCODER SRM 613 DIV2
- topcoder-srm-613-div2
- topcoder-srm-604-div2
- LWPCookieJar的使用
- INS-06006 Passwordless SSH connectivity not set up between the following node
- Caffe —— Deep learning in Practice
- 在laravel框架中如何查看自己写的sql原生格式
- poi get cell value is formula
- Topcoder SRM 616 Div2 1000 TwoLLogo
- nova-authconsole HA方案memcached配置
- OC 方法,继承,多态 练习题
- Android系统自动重启测试
- java基础
- kylin save query error
- CentOS7安装etcd和flannel
- post提交数据总结
- spring boot application.properties文件外部配置