[HDU 4135&&HDU 2841&&HDU 1695]용 척 정리+수론(난이도 증가 3 단계 곡)
33067 단어 HDU
제목 링크:http://acm.hdu.edu.cn/showproblem.php?pid=2841
제목 링크:http://acm.hdu.edu.cn/showproblem.php?pid=1695
hdu 4135
제목 의 대의: a,b,n 을 입력 하 십시오.a~b 중 몇 개의 수 와 n 의 상호 소 를 구 하 라 고?1 과 어떤 수 는 서로 담백 하 다.
문제 풀이 방향:
문 제 를 보면 우 리 는 i 가 a~b 에 속 하 는 것 을 옮 겨 다 닐 수 없다.그리고 i 가 n 과 공약수 가 있 는 지,있 으 면 서로 소 용이 없고 없 으 면 서로 소 용이 없다.시간 복잡 도 는 n^2 n 최대 100000,TLE.
이 문 제 는 용 척 의 정 리 를 써 야 한다.
우 리 는 먼저 이렇게 생각 할 수 있다.[1,n]중 몇 개의 수 와 m 의 상호 소 가 있 는 지,[1,n]중 몇 개의 수 와 m 의 상호 소(이 값 이 ans 라 고 가정 하면 상호 소 는 당연히 n-ans 이다.
문 제 는 구[1,n]중 몇 개의 수 와 m 가 서로 어 울 리 지 않 는 지 로 바 뀌 었 다.
가설 n=12,m=30
첫 번 째 단계:먼저 m 의 인자 수(m 의 인자 수 는 2,3,5)를 구한다.
두 번 째 단계:[1,n]에서 m 인자 의 배 수 는 당연히 서로 소화 되 지 않 는 다.
(2,4,6,8,10,12)->n/2 6 개, (3,6,9,12)->n/3 4 개,(5,10)->n/52 개.
급 한 게 다 겹 칠 수도 있어.서 두 르 지 마 세 요.안에 중복 되 는 것 이 있 는 지 없 는 지 우 리 는 중복 되 는 것 을 빼 야 합 니 다.
공식 n/2+n/3+n/5-n/(2*3)-n/(2*5)-n/(3*5)+n/(2*3*5).
STEP 3:중요 한 것 이 왔 다.이 단 계 는 여러 가지 방법 이 있 습 니 다.dfs,대기 열 배열,비트 연산 이 모두 가능 합 니 다.대기 열 배열 은 dfs 보다 조금 빠 릅 니 다.여기 서 나 는 두 번 째(대기 열 배열)만 말 합 니 다.우 리 는 하나의 대기 열(배열 도 괜 찮 습 니 다)으로 나타 난 분 모 를 저장 할 수 있 습 니 다.우 리 는 대기 열의 첫 번 째 요 소 를 1 로 만 들 수 있 습 니 다.매번 나타 나 는 m 의 인자 와 대기 열 에 있 는 요 소 를 하나씩 곱 해서 대기 열 에 저장 할 수 있 습 니 다.마지막 에 저 장 된 요 소 는 바로 우리 위의 분모 입 니 다.현재 의 문 제 는 우리 가 언제 사용 하고 언제 사용 하 느 냐 가 되 었 다.여기 서 우 리 는 저장 할 때마다 하나(-1)를 더 곱 하면 우리 가 원 하 는 결 과 를 얻 을 수 있다.
제목 은[a,b]에서 n 과 호상 소 를 요구 하 는데 우 리 는 각각[1,b]와 n 의 호상 소 와[1,a-1]과 n 의 호상 소 를 구 하 는 것 이 답 이다.
코드:
1 #include <iostream>
2 #include <cstdio>
3 #include <algorithm>
4 #include <cstring>
5 #include <vector>
6 using namespace std;
7 vector<int>vt;
8
9 __int64 n, a, b, res;
10 __int64 que[1024];
11
12 void fx()
13 {
14 vt.clear();
15 res=n;
16 for(int i=2; i*i<=n; i++)
17 {
18 if(res%i==0)
19 {
20 vt.push_back(i);
21 while(res%i==0)
22 res/=i;
23 }
24 }
25 if(res>1) vt.push_back(res);
26 }
27
28 __int64 cal(__int64 n, __int64 t)
29 {
30 int num=0;
31 que[num++]=1;
32 for(int i=0; i<vt.size(); i++)
33 {
34 int ep=vt[i];
35 int k=num;
36 for(int j=0; j<k; j++)
37 que[num++]=ep*que[j]*(-1);
38 }
39 __int64 sum=0;
40 for(int i=0; i<num; i++)
41 sum+=t/que[i];
42 return sum;
43 }
44
45 int main()
46 {
47 int T, tcase=0;
48 cin >> T;
49 while(T--)
50 {
51 cin >> a >> b >> n;
52 fx();
53 __int64 ans=cal(n,b)-cal(n,a-1);
54 printf("Case #%d: %I64d
",++tcase,ans);
55 }
56 return 0;
57 }
hdu 2841
제목 의 대의: N*M 의 격 점 에 나무 가 있 는데 0,0 시 에 몇 그루 의 나 무 를 볼 수 있 습 니까?
문제 풀이 방향:
그림 을 통 해 알 수 있 듯 이 A1/B1=A2/B2 는 나무 한 그루 가 보이 지 않 기 때문에 Ai/Bi 가 몇 가지 가 있 는 지 찾 아 보 는 것 이다.
A/B 에서 만약 에 A,B 가 1 보다 큰 공약수 가 있 으 면 A=A'*D B=B'*D,그러면 A/B=A'/B',즉 다른 조 의 수가 이런 것 과 같 으 면 문 제 는 몇 쌍 의 상호 질 적 인 수로 전환 되 는 지 알 수 있다.
이 문제 와 이전 문제 의 유일한 차 이 는 매 거 i 이다.1-M 에서 i 와 서로 질 적 인 수 를 찾 는 것 이다.그 중에서 1<=i<=N.
i 의 모든 소인 자 를 미리 처리 한 다음 에 용 척 구 를 하면 된다.
코드:
1 #include <iostream>
2 #include <cstdio>
3 #include <algorithm>
4 #include <cstring>
5 #include <vector>
6 using namespace std;
7
8 const int maxn=100001;
9 int que[maxn];
10 vector<int>vt[maxn];
11
12 void init()
13 {
14 for(int i=0; i<maxn; i++)
15 vt[i].clear();
16 for(int i=2; i<maxn; i++)
17 {
18 int t=i;
19 for(int j=2; j*j<=i; j++)
20 {
21 if(t%j==0)
22 {
23 vt[i].push_back(j);
24 while(t%j==0)
25 t/=j;
26 }
27 }
28 if(t>1) vt[i].push_back(t);
29 }
30 }
31
32 __int64 cal(int n, int s)
33 {
34 int num=0;
35 que[num++]=1;
36 for(int i=0; i<vt[s].size(); i++)
37 {
38 int ep=vt[s][i];
39 if(ep>n) break;
40 int k=num;
41 for(int j=0; j<k; j++)
42 {
43 que[num++]=que[j]*ep*(-1);
44 }
45 }
46 __int64 sum=0;
47 for(int i=0; i<num; i++)
48 {
49 sum+=n/que[i];
50 }
51 return sum;
52 }
53
54 int main()
55 {
56 int T, n, m;
57 init();
58 cin >> T;
59 while(T--)
60 {
61 scanf("%d%d",&n,&m);
62 __int64 ans=n;
63 for(int i=2; i<=m; i++)
64 ans+=cal(n,i);
65 printf("%I64d
",ans);
66 }
67 return 0;
68 }
hdu1695
제목:a,b,c,d,k 다섯 개 드릴 게 요.x 는[a,b]y 는[c,d]에 속한다.몇 쌍(x,y)의 공약수 가 k 냐 고 물 었 다. 주의(x,y)와(y,x)는 같은 쌍 으로 간주 합 니 다.
문제 풀이 방향:
이 문 제 는 용 반 정리+수론 소수 선별 법+수론 오로라 함 수 를 사용 했다.좋 은 문제 라 고 할 수 있다.
제목 의 첫머리 해석 을 잘 보 세 요.a=c=1 을 가상 할 수 있 습 니 다.이것 이 있 으 면 더욱 간단 합 니 다.우 리 는 먼저 점 b,d 를 각각 k,b/=k,d/=k 로 나 눌 수 있다.
b.d 보다 클 수 있 습 니 다.여기 서 우 리 는 d 가 b 보다 크 고 그렇지 않 으 면 교환 합 니 다.이렇게 하면[1,b],[1,d]중 몇 쌍 의 상호 소 수 를 찾 아야 합 니까?
우 리 는 i 를 1~d 에서 옮 겨 다 니 게 합 니 다.
1.i<=b 일 때 오로라 함수 로 상호 원소 의 대 수 를 직접 구 할 수 있 습 니 다.
2.i>b 일 때 용 반 정 리 를 이용 하여[1,b]에서 i 와 서로 소의 대 수 를 구한다.
여기 서 k=0 의 상황 을 주의 하 세 요.무시 하 는 것 은 바로 여기 running error time 에 몇 번 주의 하지 않 은 것 입 니 다.
이 문 제 는 용 반 정리 로 나 는 두 가지 방법,대열 배열 과 dfs 를 사용 하여 촉감 을 연습 했다.대기 열 배열 이 dfs 보다 배 빠르다.
코드:
1 #include <iostream>
2 #include <cstdio>
3 #include <algorithm>
4 #include <cstring>
5 #include <vector>
6 using namespace std;
7
8 const int maxn=100005;
9 int que[maxn];
10 bool color[maxn];
11 int f[maxn], phi[maxn];
12 vector<int>vt[maxn];
13
14 void Eular() //
15 {
16 phi[1]=1;
17 int k, num=0;
18 memset(color,false,sizeof(color));
19 for(int i=2; i<maxn; i++)
20 {
21 if(!color[i])
22 {
23 f[num++]=i;
24 phi[i]=i-1;
25 }
26 for(int j=0; j<num&&(k=i*f[j])<maxn; j++)
27 {
28 color[k]=true;
29 if(i%f[j]==0)
30 {
31 phi[k]=phi[i]*f[j]; break;
32 }
33 else
34 phi[k]=phi[i]*(f[j]-1);
35 }
36 }
37 }
38
39 void init() //
40 {
41 for(int i=2; i<maxn; i++)
42 {
43 int t=i;
44 for(int j=0; f[j]*f[j]<=i; j++)
45 {
46 if(t%f[j]==0)
47 {
48 vt[i].push_back(f[j]);
49 while(t%f[j]==0)
50 t/=f[j];
51 }
52 }
53 if(t>1) vt[i].push_back(t);
54 }
55 }
56
57 __int64 cal(int n, int s) //
58 {
59 int num=0;
60 que[num++]=1;
61 for(int i=0; i<vt[s].size(); i++)
62 {
63 int ep=vt[s][i];
64 if(ep>n) break;
65 int k=num;
66 for(int j=0; j<k; j++)
67 {
68 que[num++]=que[j]*ep*(-1);
69 }
70 }
71 __int64 sum=0;
72 for(int i=0; i<num; i++)
73 {
74 sum+=n/que[i];
75 }
76 return sum;
77 }
78
79 /*
80 __int64 dfs(int a, int b, int cur) //dfs
81 {
82 __int64 res=0, k;
83 for(int i=a; i<vt[cur].size(); i++)
84 {
85 k=b/vt[cur][i];
86 res+=k-dfs(i+1,k,cur);
87 }
88 return res;
89 }
90 */
91
92 int main()
93 {
94 int a, b, c, d, k, T, tcase=0;
95 Eular();
96 init();
97 cin >> T;
98 while(T--)
99 {
100 scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
101 if(k==0||k>b||k>d)
102 {
103 printf("Case %d: 0
",++tcase); continue;
104 }
105 b=b/k, d=d/k;
106 if(b>d) swap(b,d);
107 __int64 ans=0;
108 for(int i=1; i<=b; i++)
109 {
110 ans+=phi[i];
111 }
112 for(int i=b+1; i<=d; i++)
113 {
114 ans+=cal(b,i);
115 }
116 printf("Case %d: %I64d
",++tcase,ans);
117 }
118 return 0;
119 }
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[HDU] 4089 활성화 확률 DPdp[i][j]를 모두 i개인의 대기열인 Tomato가 j위 서버가 마비될 확률로 역추를 사용하면 우리는 상태 이동 방정식을 얻을 수 있다. i == 1 : dp[1][1] = dp[1][1] * p1 + dp[1]...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.