HDU - 5116(计数dp)
2015-08-31 22:05
344 查看
这个题目的难点在于(自己设计中间变量对结果进行统计)对结果的统计:
思路大概如此:
首先统计出所有的符合条件的L形有多少个记为 x,然后统计出集合相交的A,B有多少个记为y,那么结果就是x*x - y;
对于所有的L形的统计比较简单,递推计算出每个点可以往上往下延伸多长,然后计数统计。
定义cross(i,j) 为记过点i,j的所有L形,cnt[ i ][ j ] 为x 从1 -> i 并且 y 从 1 - >j 中有多少满足条件的L形, c[ i ][ j ]为x = i并且 y 从 1 - >j 中有多少满足条件的L形, u[ i ][ j ] 为向上延伸的
长度,r[i][j] 为向右延伸的长度。
对于重复的集合,要这样计算,分别统计经过一个特定转角i,j的所有重复集合对,
1 , 那么转角同为 点 i,j , 那么 总数为cnt[ i ][ j] * cnt[ i ][j];
2 , 经过点i,j 但转角不是点i,j与转交是i,j的之间的重复问题, 总数为cnt[ i ][ j ] * ( cross[i][j] - cnt[ i ][ j ]) *2
3 , 不经过点i,j 与转角是i,j点所有重复情况,那么就要沿着y轴,从i,j出发想右走,一一统计,具体见代码。
思路大概如此:
首先统计出所有的符合条件的L形有多少个记为 x,然后统计出集合相交的A,B有多少个记为y,那么结果就是x*x - y;
对于所有的L形的统计比较简单,递推计算出每个点可以往上往下延伸多长,然后计数统计。
定义cross(i,j) 为记过点i,j的所有L形,cnt[ i ][ j ] 为x 从1 -> i 并且 y 从 1 - >j 中有多少满足条件的L形, c[ i ][ j ]为x = i并且 y 从 1 - >j 中有多少满足条件的L形, u[ i ][ j ] 为向上延伸的
长度,r[i][j] 为向右延伸的长度。
对于重复的集合,要这样计算,分别统计经过一个特定转角i,j的所有重复集合对,
1 , 那么转角同为 点 i,j , 那么 总数为cnt[ i ][ j] * cnt[ i ][j];
2 , 经过点i,j 但转角不是点i,j与转交是i,j的之间的重复问题, 总数为cnt[ i ][ j ] * ( cross[i][j] - cnt[ i ][ j ]) *2
3 , 不经过点i,j 与转角是i,j点所有重复情况,那么就要沿着y轴,从i,j出发想右走,一一统计,具体见代码。
//#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <cstdlib> #include <cstdio> #include <algorithm> #include <cstring> #include <map> #include <set> #include <vector> #include <cctype> #include <cmath> #include <queue> #define ls rt<<1 #define rs rt<<1|1 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define mem(a,n) memset(a,n,sizeof(a)) #define rep(i,n) for(int i=0;i<(int)n;i++) #define rep1(i,x,y) for(int i=x;i<=(int)y;i++) using namespace std; typedef long long ll; const ll oo = 1e12; const double pi = acos(-1.0); const int inf = 0x3f3f3f3f; typedef pair<int,int> pii; typedef pair<ll,ll> pll; const int N = 205; int gcd(int a,int b){return b==0 ? a:gcd(b,a%b);} int cnt ,c ; void init(){ mem(cnt,0); rep1(i,1,N-1) rep1(j,1,N-1){ int te = 0; rep1(k,1,j) te+=(gcd(i,k)==1); cnt[i][j] = cnt[i-1][j]+(c[i][j] = te); } } bool vis ; int u ,r ,n,cr ; int main() { init(); int T,kase=1; scanf("%d",&T); while(T--){ scanf("%d",&n); mem(vis,false); rep1(i,1,n) { int x,y; scanf("%d %d",&x,&y); vis[x][y] = true; } ll ans1 = 0; mem(u,0); mem(r,0); mem(cr,0); int tem ; for(int i=200;i>=1;i--) for(int j=200;j>=1;j--)if(vis[i][j]){ u[i][j]=u[i+1][j]+vis[i+1][j]; r[i][j]=r[i][j+1]+vis[i][j+1]; ans1+=cnt[u[i][j]][r[i][j]]; mem(tem, 0); for(int k=u[i][j];k>=1;k--) tem[k] = c[k][r[i][j]]; for(int k=u[i][j];k>=1;k--) tem[k-1]+=tem[k]; for(int k=0;k<=u[i][j];k++) cr[i+k][j] += tem[k]; } ll ans2 = 0; for(int i=200;i>=1;i--) for(int j=200;j>=1;j--)if(vis[i][j]){ ll te = cnt[u[i][j]][r[i][j]]; ll yu = 0; for(int k = 1; k<=r[i][j];k++){ yu += cr[i][j+k]; ans2 += yu*c[k][u[i][j]]*2; } ans2+=te*te + (ll)(cr[i][j]- te)*te*2; } printf("Case #%d: %I64d\n",kase++,ans1*ans1-ans2); } return 0; }
相关文章推荐
- 从现在开始我要做一个幸福的人——记英语
- 惠普之旅-在这个夏天正式起航!
- 数据库设计(7)-概念数据建模
- cocos2d-js 事件交互
- Consuming a RESTful Web Service
- 【转】使用AIDL实现进程间的通信之复杂类型传递
- Android ImageView图片透明区域不响应点击事件,不规则图片透明区域响应点击事件
- [转]XML::Parser perl module is required for intltool错误
- ubuntu下tftp的安装、配置、使用
- spring 的 resource接口概览
- linux 下C语言编程库文件处理与Makefile编写
- 2015-2016-1 学期《软件工程》学生名单-- PS:教材使用《构建之法》第二版 --邹欣著
- 递归求阶乘
- 在AR9331上使用Openwrt 默认开启wifi
- Tcp通信中服务器处理客户端意外断开
- LeetCode -- House Robber
- 使用unetbootin将Linux安装到U盘
- Nginx基础笔记
- Keywords Search
- Keywords Search