FJUTOJ-周赛2016-12-16

Posted hchlqlz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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代码

 

  

以上是关于FJUTOJ-周赛2016-12-16的主要内容,如果未能解决你的问题,请参考以下文章

FJUTOJ-1384-FatMouse's Speed(DP)

T^T 1736FJUTOJ 1077排座位

题解FJUTOJ1309: Bi-shoe and Phi-shoe

FJUTOJ-3682 LRU算法的实现2 (链表+哈希)

背包形动态规划 fjutoj1380 Piggy-Bank

背包形动态规划 fjutoj2347 采药