FJUTOJ-周賽2016-12-16

 

注:fjutoj基本每週都有一次周賽,歡迎大家都來參加!

 

網址:http://59.77.139.92/index.jsp

 

 

A題:來源 POJ 2773

題意:給兩個數m和k,問第k 個和m 互素的數是多少(從1到無窮大)。

思路:

  二分 + 容斥

  先求出m 的素因子p[],數x 和m 互素就意味着x 不存在p 數組中的任意一個素因子,現在要 求n 下面不存在p[]素因子的數的數量可以轉化爲,n-存在p[]中任意一個素因子的數的個數(經典題型,用容斥可以求),現在二分(k,INF)可以求出答案。

 1 #include<stdio.h>
 2 #define N 1000010
 3 #define LL long long
 4 const LL INF = 0x7fffffffffffffff;
 5 bool pri[N];
 6 int prim[N], po=0;
 7 void Init()
 8 {
 9   for(int i=2;i<N;i++)
10   {
11     if(!pri[i]) prim[po++]=i;
12     for(int j=0;j<po&&(LL)i*prim[j]<N;j++)
13     {
14       pri[i*prim[j]]=1;
15       if(i%prim[j]==0) break;
16     }
17   }
18 }
19 
20 int data[30], co;
21 
22 void fun(int x)
23 {
24   int i=0;
25   co=0;
26   while(i<po && (LL)prim[i]*prim[i]<=x)
27   {
28     bool c=0;
29     while(x%prim[i]==0)
30     {
31       c=1;
32       x/=prim[i];
33     }
34     if(c) data[co++]=prim[i];
35     i++;
36   }
37   if(x!=1) data[co++]=x;
38 }
39 
40 void dfs(int limit, int j, LL y, LL now, LL &all)
41 {
42   if(limit==0)
43   {
44     all += y/now;
45     return ;
46   }
47   for(int i=j; i<co; i++)
48   {
49     dfs(limit-1, i+1, y, now*data[i], all);
50   }
51 }
52 LL solve(LL x)
53 {
54   LL sum=x, flag=-1;
55   for(int i=1; i<=co; i++)
56   {
57     LL all=0;
58     dfs(i, 0, x, 1, all);
59     sum+=flag*all;
60     flag *= -1;
61   }
62   return sum;
63 }
64 
65 LL er(LL l, LL r, LL x)
66 {
67   while(l<r)
68   {
69     LL mid = (l+r)/2;
70     if(solve(mid)>=x) r=mid;
71     else l=mid+1;
72   }
73   return l;
74 }
75 
76 int main()
77 {
78   Init();
79   int x,y;
80   while(~scanf("%d%d",&x, &y))
81   {
82     fun(x);
83     printf("%lld\n", er(y, INF, y));
84   }
85   return 0;
86 }
AC代碼

 

B題:來源 HDU 1730

題意:

思路:

  博弈

  很容易產生的錯誤判斷:如果兩個子相鄰,那麼這個的勝者是後手,如果不相鄰,勝者是先手,那麼判斷先手勝利的行數,最後如果是奇數則先手勝,偶數則後手勝(我因此WA了兩次...)。舉個錯誤樣例:,如果按上面思路,兩行都是先手勝,那麼應該是後手贏,但先手其實可以將第一行的紅點移動一格,這樣先手就贏了。

  事實上,這裏應該是nim博弈的模型,首先,我們可以判斷出一點,雙方的棋子只會不斷接近(如果一人後退一步,另一人可以跟進一步,保持局面不變)。接着,既然兩者只能接近,那麼就可以看作是n 堆,每一堆x個,每個玩家每輪可以拿走一個、兩個、...直至拿完。接下來就不解釋了。

 1 #include<stdio.h>
 2 int max(int a, int b) { return a>b?a:b; }
 3 int main()
 4 {
 5   int n, m, x, y;
 6   while(~scanf("%d%d",&n, &m))
 7   {
 8     int ans = 0;
 9     for(int i=0; i<n; i++)
10     {
11       scanf("%d%d",&x, &y);
12       if(x+1==y || x==y+1);
13       else ans ^= ( max(x, y) - (x+y-max(x, y)) - 1);
14     }
15     if(ans) printf("I WIN!\n");
16     else printf("BAD LUCK!\n");
17   }
18   return 0;
19 }
AC代碼

 

C題:來源 POJ 3671

題意:

思路:

  用兩個數組a[]、b[],a[i]表示i前面2的個數,b[i]表示i後面1的個數(遍歷兩遍可以求出a、b數組),如果以i 爲中心(1、2轉折點),要修改的數個數爲a[i-1]+b[i+1],遍歷一遍求出最小值即可。

 1 #include<stdio.h>
 2 #define N 30010
 3 int a[N], b[N], c[N];
 4 int main()
 5 {
 6   int n;
 7   while(~scanf("%d",&n))
 8   {
 9     a[0]=0;
10     for(int i=1; i<=n; i++)
11     {
12       scanf("%d", &c[i]);
13       if(c[i]==1) a[i]=a[i-1];
14       else a[i]=a[i-1]+1;
15     }
16     b[n+1]=0;
17     for(int i=n; i>0 ;i--)
18     {
19       if(c[i]==1) b[i]=b[i+1]+1;
20       else b[i]=b[i+1];
21     }
22     int mint = N;
23     for(int i=1; i<=n; i++)
24     {
25       if(a[i-1]+b[i+1]<mint) mint = a[i-1]+b[i+1];
26     }
27     printf("%d\n", mint);
28   }
29   return 0;
30 }
AC代碼

 

D題:來源 POJ 3663

題意:

思路:

  排序 + 二分

   對數組排序後,遍歷一遍,s-a[i]就是分界點,二分出小於等於他的第一個數,比他小的都滿足條件。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int a[20005];
 7 int er(int l, int r, int x)
 8 {
 9   while(l<r)
10   {
11     int mid = (l+r)/2;
12     if(a[mid]<=x) l=mid+1;
13     else r=mid;
14   }
15   return l;
16 }
17 
18 int main()
19 {
20   int n, m;
21   while(~scanf("%d%d",&n,&m))
22   {
23     for(int i=0; i<n; i++)
24       scanf("%d", &a[i]);
25     sort(a, a+n);
26     int ans = 0;
27     for(int i=n-1; i>0; i--)
28     {
29       int x = m-a[i];
30       int num = er(0, i, x) - 0;
31       ans += num;
32     }
33     printf("%d\n", ans);
34   }
35   return 0;
36 }
AC代碼

 

E題:來源 POJ 1028

題意:

思路:

  隨手寫個棧模擬一下就好了。

 1 #include<stack>
 2 #include<string>
 3 #include<iostream>
 4 using namespace std;
 5 
 6 string st[200];
 7 int top=0;
 8 int mt=0;
 9 
10 void push(string s)
11 {
12   st[++top]=s; mt=top;
13 }
14 
15 void pop()
16 {
17   if(top==0) cout<<"Ignored"<<endl;
18   else cout<<st[--top]<<endl;
19 }
20 
21 int main()
22 {
23   st[top]="http://www.acm.org/";
24   string s;
25   while(cin>>s)
26   {
27     if(s[0]=='Q') break;
28     if(s[0]=='V')
29     {
30       cin>>s; cout<<s<<endl;
31       push(s);
32     }
33     else if(s[0]=='B') pop();
34     else if(top==mt) cout<<"Ignored"<<endl;
35     else cout<<st[++top]<<endl;
36   }
37   return 0;
38 }
AC代碼

 

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章