Day26

Day26

今天讲的是 容斥定理 + 鸽巢原理
好好学习!!!
OJ

内容讲解

传送门

Ekka Dokka

Description:
Ekka and his friend Dokka decided to buy a cake. They both love cakes and that’s why they want to share the cake after buying it. As the name suggested that Ekka is very fond of odd numbers and Dokka is very fond of even numbers, they want to divide the cake such that Ekka gets a share of N square centimeters and Dokka gets a share of M square centimeters where N is odd and M is even. Both N and M are positive integers.

They want to divide the cake such that N * M = W, where W is the dashing factor set by them. Now you know their dashing factor, you have to find whether they can buy the desired cake or not.

Input
Input starts with an integer T (≤ 10000), denoting the number of test cases.

Each case contains an integer W (2 ≤ W < 2^63). And W will not be a power of 2.

Output
For each case, print the case number first. After that print “Impossible” if they can’t buy their desired cake. If they can buy such a cake, you have to print N and M. If there are multiple solutions, then print the result where M is as small as possible.

1
2
3
4
5
6
7
8
9
Sample Input
3
10
5
12
Sample Output
Case 1: 5 2
Case 2: Impossible
Case 3: 3 4

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
ll t, w;
ll k = 1;
scanf("%lld",&t);
while(t --)
{
scanf("%lld",&w);
ll x = 1;
if(w % 2 == 0)
{
while(w % 2 == 0)
{
x *= 2;
w /= 2;
}
printf("Case %lld: %lld %lld\n",k ++, w, x);
}
else printf("Case %lld: Impossible\n",k ++);
}
return 0;
}

How many integers can you find

Description:
Now you get a number N, and a M-integers set, you should find out how many integers which are small than N, that they can divided exactly by any integers in the set. For example, N=12, and M-integer set is {2,3}, so there is another set {2,3,4,6,8,9,10}, all the integers of the set can be divided exactly by 2 or 3. As a result, you just output the number 7.
Input
There are a lot of cases. For each case, the first line contains two integers N and M. The follow line contains the M integers, and all of them are different from each other. 0<N<2^31,0<M<=10, and the M integer are non-negative and won’t exceed 20.
Output
For each case, output the number.

1
2
3
4
5
Sample Input
12 2
2 3
Sample Output
7

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b)
{
return !b ? a : gcd(b, a % b);
}
ll lcm(ll a, ll b)
{
return (a / gcd(a, b) * b);
}
int a[11];
int main()
{
ll n, m, cnt;
ll sum, cnt1, LCM;
while(~scanf("%lld %lld",&n, &m))
{
ll x;
cnt = 0, sum = 0;
for(int i = 0; i < m; i ++)
{
scanf("%lld",&x);
if(x != 0)
{
a[cnt ++] = x;
}
}
for(int i = 1; i < (1 << cnt); i ++)
{
cnt1 = 0, LCM = 1;
for(int j = 0; j < cnt; j ++)
{
if(i >> j & 1)
{
cnt1 ++;
LCM = lcm(LCM, a[j]);
}
}
if(cnt1 % 2 == 0) sum -= (n - 1) / LCM;
else sum += (n - 1) / LCM;
}
printf("%lld\n", sum);
}
return 0;
}

Co-prime

Description:
Given a number N, you are asked to count the number of integers between A and B inclusive which are relatively prime to N.
Two integers are said to be co-prime or relatively prime if they have no common positive divisors other than 1 or, equivalently, if their greatest common divisor is 1. The number 1 is relatively prime to every integer.
Input
The first line on input contains T (0 < T <= 100) the number of test cases, each of the next T lines contains three integers A, B, N where (1 <= A <= B <= 10^15) and (1 <=N <= 10^9).
Output
For each test case, print the number of integers between A and B inclusive which are relatively prime to N. Follow the output format below.

1
2
3
4
5
6
7
8
9
10
Sample Input
2
1 10 2
3 15 5
Sample Output
Case #1: 5
Case #2: 10

Hint
In the first test case, the five integers in range [1,10] which are relatively prime to 2 are {1,3,5,7,9}.

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int aa[10001];
int main()
{
ll t, a, b, n;
ll k = 1;
cin >> t;
while(t --)
{
ll cnt = 0;
cin >> a >> b >> n;
for(int i = 2; i * i <= n; i ++)
{
if(n % i == 0)
aa[++ cnt] = i;
while(n % i == 0)
n = n / i;
}
if(n != 1)
aa[++ cnt] = n;
ll sum = 0;
for(int i = 1; i < (1 << cnt); i ++)
{
ll ans = 0, sum1 = 1;
for(int j = 0; j < cnt; j ++)
{
if(1 & (i >> j))
{
sum1 = sum1 * aa[j + 1];
ans ++;
}
}
if(ans & 1)
{
sum += b / sum1;
sum -= (a - 1) / sum1;
}
else
{
sum -= b / sum1;
sum += (a - 1) / sum1;
}
}
printf("Case #%d: %lld\n", k ++, b - a + 1 - sum);

}


return 0;
}

Find a multiple

Description:
The input contains N natural (i.e. positive integer) numbers ( N <= 10000 ). Each of that numbers is not greater than 15000. This numbers are not necessarily different (so it may happen that two or more of them will be equal). Your task is to choose a few of given numbers ( 1 <= few <= N ) so that the sum of chosen numbers is multiple for N (i.e. N * k = (sum of chosen numbers) for some natural number k).
Input
The first line of the input contains the single number N. Each of next N lines contains one number from the given set.
Output
In case your program decides that the target set of numbers can not be found it should print to the output the single number 0. Otherwise it should print the number of the chosen numbers in the first line followed by the chosen numbers themselves (on a separate line each) in arbitrary order.

If there are more than one set of numbers with required properties you should print to the output only one (preferably your favorite) of them.

1
2
3
4
5
6
7
8
9
10
11
Sample Input
5
1
2
3
4
1
Sample Output
2
2
3

这一题的解不是固定的
code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
typedef long long ll;
const int maxx = 1e5;
int a[maxx];
int sum[maxx];
int main()
{
int n;
scanf("%d",&n);
memset(sum, 0, sizeof sum);
for(int i = 1; i <= n; i ++)
{
scanf("%d",&a[i]);
sum[i] = (sum[i - 1] + a[i]) % n;
}
for(int i = 0; i <= n; i ++)
{
for(int j = i + 1; j <= n; j ++)
{
if(sum[i] == sum[j])
{
printf("%d\n",j - i);
for(int k = i + 1; k <= j; k ++)
{
cout << a[k] << endl;
}
return 0;
}
}
}

return 0;
}

//另一种写法
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
typedef long long ll;
const int maxx = 1e6;
int a[maxx];
int sum[maxx];
int b[maxx];
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(sum, 0, sizeof sum);
memset(b, 0, sizeof b);
for(int i = 1; i <= n; i ++)
{
scanf("%d",&a[i]);
sum[i] = (sum[i - 1] + a[i]) % n;
}
for(int i = 1; i <= n; i ++)
{
if(sum[i] == 0)
{
printf("%d\n",i);
for(int j = 1; j <= i; j ++)
{
if(j != 1)
printf(" %d", a[j]);
else
printf("%d",a[j]);
}
break;
}
if(b[sum[i]] == 0)
b[sum[i]] = i;
else
{
printf("%d\n",i - b[sum[i]]);
for(int j = b[sum[i]] + 1; j <= i; j ++)
{
if(j != b[sum[i]] + 1) printf(" %d",a[j]);
else printf("%d",a[j]);
}
break;
}
}
}
return 0;
}

吃糖果

Description:
HOHO,终于从Speakless手上赢走了所有的糖果,是Gardon吃糖果时有个特殊的癖好,就是不喜欢将一样的糖果放在一起吃,喜欢先吃一种,下一次吃另一种,这样;可是Gardon不知道是否存在一种吃糖果的顺序使得他能把所有糖果都吃完?请你写个程序帮忙计算一下。
Input
第一行有一个整数T,接下来T组数据,每组数据占2行,第一行是一个整数N(0<N<=1000000),第二行是N个数,表示N种糖果的数目Mi(0<Mi<=1000000)。
Output
对于每组数据,输出一行,包含一个”Yes”或者”No”。

1
2
3
4
5
6
7
8
9
10
11
12
Sample Input
2
3
4 1 1
5
5 4 3 2 1
Sample Output
No
Yes


Please use function scanf

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx = 1e7 + 10;
int a[maxx];
ll sum;
int main()
{
ll t, n;
scanf("%lld",&t);
while(t --)
{
sum = 0;
scanf("%lld",&n);
for(int i = 1; i <= n; i ++)
{
scanf("%d",&a[i]);
sum += a[i];
}
sort(a + 1, a + n + 1);
if(a[n] <= sum - a[n] + 1)
printf("Yes\n");
else
printf("No\n");
}

return 0;
}

Teacher Bo

Description:
Teacher BoBo is a geography teacher in the school.One day in his class,he marked N points in the map,the i-th point is at (Xi,Yi).He wonders,whether there is a tetrad (A,B,C,D)(A<B,C<D,A≠CorB≠D) such that the manhattan distance between A and B is equal to the manhattan distance between C and D.

If there exists such tetrad,print “YES”,else print “NO”.
Input
First line, an integer T. There are T test cases.(T≤50)

In each test case,the first line contains two intergers, N, M, means the number of points and the range of the coordinates.(N,M≤105).

Next N lines, the i-th line shows the coordinate of the i-th point.(Xi,Yi)(0≤Xi,Yi≤M).
Output
T lines, each line is “YES” or “NO”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Sample Input
2
3 10
1 1
2 2
3 3
4 10
8 8
2 3
3 3
4 4
Sample Output
YES
NO

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx = 1e5 + 10;
map<int, int > mp;
struct node{
int x, y;
}e[maxx];
int main()
{
int t, n, m;
scanf("%d",&t);
while(t --)
{
for(int i = 1; i <= n; i ++)
mp.clear();
scanf("%d %d",&n, &m);
for(int i = 1; i <= n; i ++)
{
scanf("%d %d",&e[i].x, &e[i].y);
}
int cnt = 0, flag = 0;
for(int i = 1; i <= n; i ++)
{
for(int j = i + 1; j <= n; j ++)
{
int x = abs(e[i].x - e[j].x) + abs(e[i].y - e[j].y);
mp[x] ++;
if(mp[x] >= 2)
{
flag = 1;
break;
}
}
if(flag) break;
}
if(flag) puts("YES");
else puts("NO");

}
return 0;
}

跳蚤

Description:
Z城市居住着很多只跳蚤。在Z城市周六生活频道有一个娱乐节目。一只跳蚤将被请上一个高空钢丝的正中央。钢丝很长,可以看作是无限长。节目主持人会给该跳蚤发一张卡片。卡片上写有N+1个自然数。其中最后一个是M,而前N个数都不超过M,卡片上允许有相同的数字。跳蚤每次可以从卡片上任意选择一个自然数S,然后向左,或向右跳S个单位长度。而他最终的任务是跳到距离他左边一个单位长度的地方,并捡起位于那里的礼物。
比如当N=2,M=18时,持有卡片(10, 15, 18)的跳蚤,就可以完成任务:他可以先向左跳10个单位长度,然后再连向左跳3次,每次15个单位长度,最后再向右连跳3次,每次18个单位长度。而持有卡片(12, 15, 18)的跳蚤,则怎么也不可能跳到距他左边一个单位长度的地方。
当确定N和M后,显然一共有M^N张不同的卡片。现在的问题是,在这所有的卡片中,有多少张可以完成任务。
Input
两个整数N和M(N <= 15 , M <= 100000000)。
Output
可以完成任务的卡片数。

1
2
3
4
5
6
7
8
Sample Input
2 4
Sample Output
12
Hint
12张卡片分别是:
(1, 1, 4), (1, 2, 4), (1, 3, 4), (1, 4, 4), (2, 1, 4), (2, 3, 4),
(3, 1, 4), (3, 2, 4), (3, 3, 4), (3, 4, 4), (4, 1, 4), (4, 3, 4)

设卡片号为 a1,a2,…,an,m,跳蚤跳到对应号的次数是 x1,x2,…,xn,跳 m 个单位长度的次数是 xn+1
那么问题就转化为求:a[1]x1+a[2]x2+…+a[n]xn+mx(n+1)=1,一共有多少种情况而上述公式实质是求:GCD(a1,a2,…,an,m)=1
故先对 m 进行素因子分解,求出总的排列组合个数,即有:m^n 种,再根据容斥定理排除公因子非 1 的情况即可
设 g 为公因子非 1 的情况数,f(i) 表示有 i 个公因子的情况数,根据奇加偶减,有:g=f(1)-f(2)+f(3)-…f(k)
设g为公因子非1的情况数,f(i) 表示有 i 个公因子的情况数,由容斥原理得:g = f(1) - f(2) + f(3) -… f(k)

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include<iostream>
#include<stdio.h>
using namespace std;
typedef long long ll;
const int maxx = 111;
int a[maxx], num;
void get_prime(ll n)
{
num = 0;
for(int i = 2; i * i <= n; i ++)
{
if(n % i == 0)
{
a[++ num] = i;
while(n % i == 0)
{
n = n / i;
}
}
}
if(n > 1) a[++ num] = n;
}
ll quick_pow(ll a, ll b)
{
ll res = 1;
while(b)
{
if(b & 1) res = res * a;
b >>= 1;
a = a * a;
}
return res;
}
ll temp, ans;
int aa[110], n, m;
void dfs(int b, int cnt, int c)
{
if(cnt == c)
{
int x = m;
for(int i = 1; i <= c; i ++)
{
x = x / aa[i];
}
temp += quick_pow(x, n);
return ;
}
for(int i = b + 1; i <= num; i ++)
{
aa[cnt + 1] = a[i];
dfs(i, cnt + 1, c);
}
}
int main()
{
while(~scanf("%d %d",&n, &m))
{
ans = 0;
get_prime(m);
for(int i = 1; i <= num; i ++)
{
temp = 0;
dfs(0, 0, i);
if(i & 1) ans += temp;
else ans -= temp;
}
ans = quick_pow(m, n) - ans;
printf("%lld\n",ans);
}
return 0;
}

---------------- The End ----------------
0%