转一道容斥原理的题
源出處:https://blog.csdn.net/qingshui23/article/details/51077728
POJ 3904 Sky Code (容斥原理)
2016年04月06日 19:53:49
閱讀數:827
傳送門
Sky Code
| Time Limit:?1000MS | ? | Memory Limit:?65536K |
| Total Submissions:?2027 | ? | Accepted:?650 |
Description
Stancu likes space travels but he is a poor software developer and will never be able to buy his own spacecraft. That is why he is preparing to steal the spacecraft of Petru. There is only one problem – Petru has locked the spacecraft with a sophisticated cryptosystem based on the ID numbers of the stars from the Milky Way Galaxy. For breaking the system Stancu has to check each subset of four stars such that the only common divisor of their numbers is 1. Nasty, isn’t it? Fortunately, Stancu has succeeded to limit the number of the interesting stars to N but, any way, the possible subsets of four stars can be too many. Help him to find their number and to decide if there is a chance to break the system.
Input
In the input file several test cases are given. For each test case on the first line the number N of interesting stars is given (1 ≤ N ≤ 10000). The second line of the test case contains the list of ID numbers of the interesting stars, separated by spaces. Each ID is a positive integer which is no greater than 10000. The input data terminate with the end of file.
Output
For each test case the program should print one line with the number of subsets with the asked property.
Sample Input
4 2 3 4 5 4 2 4 6 8 7 2 3 4 5 7 6 8Sample Output
1 0 34Source
Southeastern European Regional Programming Contest 2008
題目大意:
給出n(n<10000)個數,這些數<=10000,讓你求的就是 GCD(a,b,c,d) == 1的個數,注意必須是 4 個數
解題思路:
其實這個題一開始做就像暴力,可是自己又暴不明白,因為 他把這個題歸入容斥原理,所以就考慮GCD(a,b,c,d) ?== 1的反面就是 GCD(a,b,c,d) ?!= 1,那么a, b, c, d 必定有同樣的因子,所以 :
第一步:計算n個數字選四個總共有多少種選法[ C(n,4) ],然后減去公約數不是1的。
第二步:由一個素因子組合成的四個數的組合數?+ 由兩個素因子組合成的四個數的組合數 -....+..(奇加偶減)
第三步:進行二進制枚舉,在枚舉的時候要用到兩個數組 ,_cnt[]:記錄當前因子是由多少個素因子組成, sum[]:記錄當前因子的個數
第四步:我們先考慮將每一個數 進行素因子分解,在這里完全可以采用暴力也就是 O(sqrt(n))的算法,因為數據不是很大,當然也可以直接進行素數篩,我采用的就是素數篩。
最后一步:假設a是2的因子的個數,b是3的因子的個數,c是6的因子的個數,就是C(n,4) - C(a,4) - C(b,4) + C(c,4)
容斥原理,與第一步差不多...
PS:我還用了輸入輸出外掛,果然快呀 ^_^
My Code:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 1e4+5;
typedef long long LL;
int Scan()///輸入外掛
{
? ? int res=0,ch,flag=0;
? ? if((ch=getchar())=='-')
? ? ? ? flag=1;
? ? else if(ch>='0'&&ch<='9')
? ? ? ? res=ch-'0';
? ? while((ch=getchar())>='0'&&ch<='9')
? ? ? ? res=res*10+ch-'0';
? ? return flag?-res:res;
}
void Out(LL a)///輸出外掛
{
? ? if(a>9)
? ? ? ? Out(a/10);
? ? putchar(a%10+'0');
}
?
int p[MAXN];
bool prime[MAXN];
int k;
void isprime()///素數篩
{
? ? k = 0;
? ? LL i, j;
? ? memset(prime,false,sizeof(prime));
? ? for(i=2; i<MAXN; i++)
? ? {
? ? ? ? if(!prime[i])
? ? ? ? {
? ? ? ? ? ? p[k++] = i;
? ? ? ? ? ? for(j=i*i; j<MAXN; j+=i)
? ? ? ? ? ? ? ? prime[j] = true;
? ? ? ? }
? ? }
}
int fac[MAXN/100],num[100], cnt;
void Dec(int m)///素因子分解
{
? ? cnt = 0;
? ? memset(num, 0, sizeof(num));
? ? for(int i=0; p[i]*p[i]<=m&&i<k; i++)
? ? {
? ? ? ? if(m%p[i]==0)
? ? ? ? {
? ? ? ? ? ? fac[cnt] = p[i];
? ? ? ? ? ? while(m%p[i]==0)
? ? ? ? ? ? {num[cnt]++;
? ? ? ? ? ? ? ? m /= p[i];
? ? ? ? ? ? }
? ? ? ? ? ? cnt++;
? ? ? ? }
? ? }
? ? if(m > 1)
? ? {
? ? ? ? fac[cnt] = m;
? ? ? ? num[cnt++]=1;
? ? }
? ? ///cout<<cnt<<endl;
? ? ///cout<<fac[0]<<" "<<fac[1]<<endl;
}
int sum[MAXN];///記錄當前因子的個數
int _cnt[MAXN];///記錄當前因子是由多少個素因子組成
void Get(int m)
{
? ? Dec(m);
? ? for(int i=1; i<(1<<cnt); i++)
? ? {
? ? ? ? int s = 0;
? ? ? ? LL ans = 1;
? ? ? ? for(int j=0; j<cnt; j++)
? ? ? ? {
? ? ? ? ? ? if(i & (1<<j))
? ? ? ? ? ? {
? ? ? ? ? ? ? ? s++;
? ? ? ? ? ? ? ? ans *= fac[j];
? ? ? ? ? ? ? ? if(ans > m)
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? sum[ans]++;
? ? ? ? _cnt[ans] = s;
? ? }
}
LL ak[MAXN];///C(n,4)
void RongChi()
{
? ? memset(ak,0,sizeof(ak));
? ? for(LL i=4; i<MAXN; i++)
? ? ? ? ak[i] = i*(i-1)*(i-2)*(i-3)/24;
}
int main()
{
? ? RongChi();
? ? isprime();
? ? ///Dec(1);
? ? int n, x;
? ? while(~scanf("%d",&n))
? ? {
? ? ? ? memset(sum, 0, sizeof(sum));
? ? ? ? int m = n;
? ? ? ? while(m--)
? ? ? ? {
? ? ? ? ? ? x = Scan();
? ? ? ? ? ? Get(x);
? ? ? ? }
? ? ? ? LL ret = 0;
? ? ? ? for(int i=0; i<MAXN; i++)
? ? ? ? {
? ? ? ? ? ? if(sum[i])
? ? ? ? ? ? {
? ? ? ? ? ? ? ? if(_cnt[i] & 1)
? ? ? ? ? ? ? ? ? ? ret += ak[sum[i]];
? ? ? ? ? ? ? ? else
? ? ? ? ? ? ? ? ? ? ret -= ak[sum[i]];
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? LL ans = ak[n] - ret;
? ? ? ? Out(ans);
? ? ? ? puts("");
? ? }
? ? return 0;
}
?
轉載于:https://www.cnblogs.com/linruier/p/9513855.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
- 上一篇: numpy reshape resiz
- 下一篇: Oracle删库跑路