单挑养成计划【3】 AtCoder Grand Contest 003

B - Simplified mahjong

题意:有一组面值为1~N的牌,已知每种面值的个数,卡牌a,b可以组成一对(a, b)当且仅当|a面值 - b面值|<=1。问最多能组多少对。

题解: 没什么好说的,贪心O(n)扫一遍就好。需要注意的是三张相邻面值的卡牌分别有1 2 1张,这种情况可以组成两对。贪心的姿势一定要选对。

 1 #include <cstdio>
 2 #include <vector>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <iostream>
 6 #include <algorithm>
 7 using namespace std;
 8 typedef long long LL;
 9 const int maxn = 100005;
10 const int mod = 1e9 + 7;
11  
12 int main() {
13     int n,a[maxn];
14     LL ans = 0;
15     cin>>n;
16     for (int i=0; i<n; i++) {
17         cin >> a[i];
18     }
19     for (int i=0; i<n; i++) {
20         ans += a[i]>>1;
21         a[i] %= 2;
22         if (i<n-1 && a[i] && a[i+1]) {
23             ans++;
24             a[i]--, a[i+1]--;
25         }
26     }
27     cout<<ans<<endl;
28     return 0;
29 }
View Code

 

C - BBuBBBlesort!

题意:给你一串数,数组中的数两两不同。现在有两种操作,操作1把相邻的两个数翻转,操作2把相邻的三个数翻转,问使这个数组升序排列的最少的操作1的次数。

题解:观察一下两个操作的性质,从奇偶性入手,发现操作2完成后数字所在位置的奇偶性不变。所处位置和应处位置奇偶性不同的时候,就必须使用操作1。扫一遍即可。

 1 #include <cstdio>
 2 #include <vector>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <iostream>
 6 #include <algorithm>
 7 using namespace std;
 8 typedef long long LL;
 9 const int maxn = 100005;
10 const int mod = 1e9 + 7;
11 struct node {
12     int x,i;
13     bool operator <(const node &rhs)const {
14         return x < rhs.x;
15     }
16 }a[maxn];
17 int main() {
18     int n,ans=0;
19     cin>>n;
20     for (int i=0; i<n; i++) {
21         cin>>a[i].x;a[i].i = i;
22     }
23     sort(a, a+n);
24     for (int i=0; i<n; i++) {
25         if (!(i&1) && a[i].i&1) {
26             ans++;
27         }
28     }
29     cout<<ans<<endl;
30     return 0;
31 }
View Code

 

D - Anticube

题意:一串数,求它最大的两两相乘非立方数的子集规模。

题解:两两相乘求得的最大立方数是1e10*1e5=1e15。10^15以内立方数很少,只有1e5,就想到分组做。对每一个数,考虑它本身以及和它相乘出立方数的数,这两个数中间必然是二选一的。对1这种自己乘自己的特判一下就好。

 1 #include <map>
 2 #include <cmath>
 3 #include <cstdio>
 4 #include <vector>
 5 #include <cstdlib>
 6 #include <cstring>
 7 #include <iostream>
 8 #include <algorithm>
 9 using namespace std;
10 typedef long long LL;
11 const int maxn = 100005;
12 const int mod = 1e9 + 7;
13 LL a[maxn], b[maxn], aa[maxn], bb[maxn];
14 map<LL, int> mp;
15 vector<int> p;
16 #define N 1234
17 bool vis[N];
18 void pre() {
19     for (int i=2; i<N; i++) {
20         if (!vis[i]) {
21             p.push_back(i);
22             for (int j=i+i; j<N; j+=i) {
23                 vis[j] = 1;
24             }
25         }
26     }
27 }
28 int main() {
29     int n,ans=0;
30     pre();
31     cin>>n;
32     for (int i=0; i<n; i++) {
33         cin>>a[i];b[i]=a[i];
34     }
35     for (int i=0; i<n; i++) {
36         aa[i] = 1, bb[i] = 1;
37         for (int j=0; j<p.size(); j++) {
38             int cnt = 0;
39             while (a[i] % p[j] == 0) {
40                 a[i] /= p[j];
41                 cnt++;
42             }
43             if (cnt % 3 == 1) {
44                 aa[i] *= p[j]; bb[i] *= p[j] * p[j];
45             } else if (cnt % 3 == 2) {
46                 bb[i] *= p[j]; aa[i] *= p[j] * p[j];
47             }
48         }
49         aa[i] *= a[i];
50         LL t = floor(sqrt(a[i]*1.0));
51         if (t * t == a[i]) bb[i] *= t;
52         else {
53             if (bb[i]*a[i]>0 && bb[i]*a[i]*a[i]>0) bb[i] *= a[i] * a[i];
54             else bb[i] = 0;
55         }
56         mp[aa[i]]++;
57     }
58     //for (int i=0; i<n; i++) {
59     //    cout<<b[i]<<": "<<aa[i]<<" "<<bb[i]<<endl;
60     //}
61     int flag = 0;
62     for (int i=0; i<n; i++) {
63         if (aa[i] == 1) {
64             if (flag == 0) {ans++; flag=1;}
65         } else {
66             ans += max(mp[aa[i]], mp[bb[i]]);
67             mp[aa[i]] = mp[bb[i]] = 0;
68         }
69     }
70     cout<<ans<<endl;
71     return 0;
72 }
View Code

 

E - Sequential operations on Sequence

题意:一串数,初始为1~N,现在给q个操作,每次操作把数组长度变为qi,新增的数为上一个操作后的数组的重复。问q次操作后1~N每个数出现了多少次。

题解:首先很容易发现如果q[i]>=q[i+1],那么q[i]是毫无意义的。扫一遍之后,我们有了一个递增的数组v。但是极限数据下复杂度并没有下降,直接操作肯定不行,那怎么办呢?转换一下思路,从最后一步往前推——诶是不是感觉很眼熟?假设现在在操作k=v[i],那么我们找到v[i-1],更新i-1对应的值,然后把k的值更新成k%v[i-1]接着循环,最后从尾到头加起来就是答案。证明很麻烦啊…简要说一下就是每次操作,都把上一次重复了floor(k/v[i-1])遍同时再重复一次前k%v[i-1]个数,同时因为这个数组一开始是顺序的,后面数的存在一定对前面的数做对应的贡献,所以只要找到这两个关键点进行更新,那么就可以保证答案的正确性…

!!注意对特殊情况的处理!!比如q=0……比如当所有q[i]都比n大,在处理数组的时候应该判断v的开头是否应该加入n【但是这个数据里好像没有?蜜汁数据。。居然有一大半的q都等于0。。逗呢。。

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <iostream>
 6 #include <vector>
 7 #include <queue>
 8 using namespace std;
 9 typedef  long long  ll;
10 const int maxn = 2e5 + 5;
11 int n, q;
12 ll a, t[maxn], ans[maxn];
13 vector<ll> v;
14 int main() {
15     scanf("%d %d",&n,&q);
16     v.push_back(n);//!!!
17     for (int i=0; i<q; i++) {
18         scanf("%lld",&a);
19         while (v.size() && v.back() >= a)
20             v.pop_back();
21         v.push_back(a);
22     }
23     //for (int i=0; i<v.size(); i++) cout<<v[i]<<"  ";
24     t[v.size() - 1] = 1;
25     for (int i=v.size()-1; i>=0; i--) {
26         ll k = v[i];
27         //cout<<endl<<i<<" : \n";
28         while (k > v[0]) {
29             int j = lower_bound(v.begin(), v.end(), k) - (v.begin() + 1);
30             t[j] += k / v[j] * t[i];
31             //cout<<k<<" "<<j<<" : "<<v[j]<<" "<<t[j]<<" "<<t[i]<<endl;
32             k %= v[j];
33         }
34         ans[k] += t[i];
35     }
36     for (int i=n-1; i>=1; i--) ans[i] += ans[i+1];
37     for (int i=1; i<=n; i++)
38         printf("%lld\n", ans[i]);
39     return 0;
40 }
View Code

 

F - Fraction of Fractal

我尽力了。。读不懂题。。。、、

posted on 2016-10-27 18:34  HoneyCat  阅读(467)  评论(0编辑  收藏  举报

导航