POJ 3904 Sky Code 解题报告(容斥原理)
来源:互联网 发布:购买汽车配件的软件 编辑:程序博客网 时间:2024/05/19 16:21
Description
Input
Output
Sample Input
42 3 4 5 42 4 6 8 72 3 4 5 7 6 8
Sample Output
1 0 34
Source
解题报告: 个人觉得挺难的一道题。
分析,题目让我们求的是互质4元组的数量,我们可以求出gcd(a, b, c, d)>1的4元组的数量,用C(n, 4)减去即为答案。
听起来和之前几篇博客的题目都差不多,但这次的数据并不是连续唯一的,而是离散的。10000个数,1-10000。
所以问题出现了。当计算素因子为2的数的组合时,如果遍历一遍复杂度就是10000,总复杂度就是10000*10000,这是不可接受的。
在下不才,想不出什么比较好的方法,但是又不想看题解,所以决定打表。我们事先计算好1-10000每个数所有的因子数。注意,是因子。如果存在2这个因子,那么cnt[2]++。最后计算时,存在共因子2的四元组的数量就是C(cnt[2], 4),存在共因子3的四元组的数量就是C(cnt[3], 4),存在共因子2和3的四元组的数量就是C(cnt[2], 4)+C(cnt[3], 4)-C(cnt[6], 4)。此处使用容斥定理即可。
当然,表太长,POJ不让交,故程序初始化时打表。用CodeBlocks测试了一下,打表的时间大概是250MS。POJ上总时间860MS。
本次写此报告并不是说我的方法好,而是如果比赛的时候想不出什么优秀算法,想出不超时的方法一样能A题。当然,事后还是要学习一下大牛们好的算法,或者自己再想想,优化一下。
笔者的代码如下:
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long LL;const int maxn = 10001;int deg[maxn], cnt[maxn];bool good[maxn];int table[maxn][65];LL c4(int v){ return (long long)v*(v-1)*(v-2)*(v-3)/24;}LL cal(){ memset(deg, 0, sizeof(deg)); memset(good, 1, sizeof(good)); LL ans = 0; for(int i=2;i<maxn;i++) { if(good[i]) { if(deg[i]==0) deg[i]=1; LL t = cnt[i]; if(deg[i]&1) ans+=c4(cnt[i]); else ans-=c4(cnt[i]); for(int j=2;i*j<=maxn;j++) { if(deg[i]==1) if(j%i==0) good[i*j]=false; else deg[i*j]++; } } } return ans;}void init(){ for(int i=1;i<maxn;i++) { int top=0; for(int j=2;j<=i;j++) if(i%j==0) table[i][top++] = j; }}int main(){ init(); int n; while(~scanf("%d", &n)) { memset(cnt, 0, sizeof(cnt)); for(int i=0;i<n;i++) { int tmp; scanf("%d", &tmp); for(int j=0;table[tmp][j];j++) cnt[table[tmp][j]]++; } printf("%lld\n", c4(n) - cal()); }}
搜了别人的解题报告,大家应该都是直接对每个数进行因式分解,然后奇偶也记录下来,最后一次完成统计求和。
自己然后写的代码,时效110MS,代码如下:
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long LL;const int maxn = 10010;LL c4[maxn];int factor[maxn], prime[maxn];bool vis[maxn];void init(){ for(int i=4;i<maxn;i++) c4[i] = (long long)i*(i-1)*(i-2)*(i-3)/24;}void decomposition(int n){ int top=0; for(int i=2;i*i<=n;i++) if(n%i==0) { prime[top++] = i; while(n%i==0) n/=i; } if(n>1) prime[top++] = n; for(int i=1;i<(1<<top);i++) { int tmp = 1; bool flag = false; for(int j=0;j<top;j++) if(i&(1<<j)) tmp*=prime[j], flag = !flag; factor[tmp]++; vis[tmp]=flag; }}int main(){ init(); int n; while(~scanf("%d", &n)) { LL ans = -c4[n]; memset(vis, 0, sizeof(vis)); memset(factor, 0, sizeof(factor)); for(int i=0;i<n;i++) { int tmp; scanf("%d", &tmp); decomposition(tmp); } for(int i=2;i<maxn;i++) if(factor[i]) { if(vis[i]) ans+=c4[factor[i]]; else ans-=c4[factor[i]]; } printf("%lld\n", -ans); }}
- POJ 3904 Sky Code 解题报告(容斥原理)
- POJ 3904 Sky Code 容斥原理
- poj 3904 sky code 容斥原理
- POJ 3904 Sky Code 容斥原理
- poj 3904 Sky Code【容斥原理】
- 容斥原理:poj 3904 Sky Code
- Sky Code - POJ 3904 容斥原理
- Sky Code - POJ 3904 容斥原理
- POJ 3904 Sky Code (容斥原理)
- POJ 3904 Sky Code (容斥原理)
- POJ 3904 Sky Code (容斥原理)
- poj 3904 Sky Code(容斥原理)
- POJ 3904 Sky Code (容斥原理)
- POJ 3904 Sky Code(容斥)
- POJ 3904 Sky Code(容斥)
- [容斥原理] poj 3094 Sky Code
- POJ 3904:Sky Code _容斥原理
- poj3904 Sky Code(容斥原理)
- codec engine代码阅读一---根目录下的package.xdc
- java工厂模式的三种方式
- 求2+22+222+2222+22222的值
- 2014ACM集训13级PK赛2-Somali Pirates
- PHP学习3 查询
- POJ 3904 Sky Code 解题报告(容斥原理)
- android手势检测类的扩展支持单点和多点触摸
- codec engine代码阅读二---根目录下的release notes
- 编写计算“两个整数的最大公约数”程序。 要求通过键盘输入两个整数、检查输入整数是否符合要求,并计算出其最大公约数。
- php中单引号和双引号的区别
- cocos2d-x中的CCArray
- PHP学习4 查询
- bjam.exe stage --toolset=msvc-12.0 vs2013 编译boost
- codec engine代码阅读三---example文件夹