单挑养成计划【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 }
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 }
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 }
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 }
F - Fraction of Fractal
我尽力了。。读不懂题。。。、、