DIV2 :
题意:给你两列数和一个数k,问这两列数是否完全包含1-k。
解法:可以排序之后模拟,我为了省掉排序和判断重复用了个set(我是set控~)。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <set> 4 #include <algorithm> 5 using namespace std; 6 7 set<int> s; 8 set<int>::iterator it; 9 10 int main() { 11 int n, p; 12 scanf("%d", &n); 13 scanf("%d", &p); 14 for(int i = 0; i < p; i++) { int a; scanf("%d", &a); s.insert(a);} 15 scanf("%d", &p); 16 for(int i = 0; i < p; i++) { int a; scanf("%d", &a); s.insert(a);} 17 int c = 1; 18 for(it = s.begin(); it != s.end(); it++) { 19 if(*it == c) c++; 20 else break; 21 } 22 if(c > n) puts("I become the guy."); 23 else puts("Oh, my keyboard!"); 24 25 return 0; 26 }
题意:给你两个人的在线时间。一个人是固定的n个区间[a1, b1], [a2, b2], ..., [an,bn]。另一个人的在线时间是与起床时间t有关的m个区间,会输入l,r表示l <= t <= r。然后这个人的在线时间为[c1 + t, d1 + t], [c2 + t, d2 + t], ..., [cm + t, dm + t]。询问有多少个满足要求的起床时间使得两个人的在线时间有交集(只有一个时刻也可以)。
解法:枚举t,之后判断区间组是否相交。为了好写我们可以对两个人的区间内的数都+1,然后扫描观察是否有等于2的数。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <set> 4 #include <algorithm> 5 using namespace std; 6 7 int u[1010], a[60], b[60], c[60], d[60]; 8 9 int main() { 10 int p, q, l, r, ans = 0; 11 scanf("%d%d%d%d", &p, &q, &l, &r); 12 for(int i = 0; i < p; i++) scanf("%d%d", &a[i], &b[i]); 13 for(int i = 0; i < q; i++) scanf("%d%d", &c[i], &d[i]); 14 for(int i = l; i <= r; i++) { 15 int f = 0; 16 memset(u, 0, sizeof(u)); 17 for(int j = 0; j < p; j++) for(int t = a[j]; t <= b[j]; t++) u[t]++; 18 for(int j = 0; j < q; j++) for(int t = c[j] + i; t <= d[j] + i; t++) if(t <= 1000) u[t]++; 19 for(int j = 0; j <= 1000; j++) if(u[j] >= 2) f = 1; 20 ans += f; 21 } 22 printf("%d ", ans); 23 24 return 0; 25 }
DIV1:
A.24 Game
题意:给你1, 2, ..., n-1, n 这个序列,每次你可以取出两个数做+/-/*三种操作之一,然后把结果放回到序列中,询问能否是的这个序列最后只剩下一个24。
解法:首先很明显n < 4的时候是无解的。如果n=4,那么1 * 2 * 3 * 4=24,如果n=5,那么(5 - 1 - 2) * 3 * 4 = 24。若n > 5,那么我可以做n - (n - 1) = 1,相当于变成了n-2时候的情况加一个1,那么显然最后让答案乘上这个1即可。
代码:
include <cstdio> #include <algorithm> #include <map> #include <vector> #include <string> #include <cstring> using namespace std; const int N = 500010; int a[N]; int main() { int n; while( scanf("%d", &n) != EOF ) { if(n <= 3) { printf("NO "); continue; } else if(n % 2 == 0) { printf("YES "); int k = 0; for(int i = 5; i < n; i += 2) { printf("%d - %d = 1 ", i + 1, i); k++; } printf("1 * 2 = 2 "); printf("2 * 3 = 6 "); printf("6 * 4 = 24 "); for(int i = 0; i < k; i++) printf("1 * 24 = 24 "); } else { printf("YES "); int k = 0; for(int i = 6; i < n; i += 2) { printf("%d - %d = 1 ", i + 1, i); k++; } printf("5 - 1 = 4 "); printf("4 - 2 = 2 "); printf("2 * 3 = 6 "); printf("6 * 4 = 24 "); for(int i = 0; i < k; i++) printf("1 * 24 = 24 "); } } return 0; }
B.Two Sets
题意:给你一列两两不同的数v[i],然后两个正整数a,b,现在希望把序列v中的每个数都分到两个集合中的一个。假设两个集合为s,t,那么若x∈s,则a-x∈s,类似的有若x∈t,则b-x∈t。询问这列数能否被成功划分到两个集合。
解法:首先我们假设a<b。我们考虑现在这列数中最小的数,假设为x。若b-x在序列v中存在,那么我一定会把x和b-x都放到集合t中。因为如果我不把b-x和x放到t中,那么b-x这个元素就永远无法被任何其他的元素匹配了。原因是假设又另一个元素能和b-x匹配,我们设这个元素为y,由于x是当前序列中的最小值,那么y>x,则有y+b-x>b,那么显然和y+b-x=b矛盾。然后还需要考虑的就是有可能2 * x = a或 2 * x = b,这种特殊考虑一下就好了。呃,我的代码由于没想清楚写的比较复杂,思路也不完全是上述的思路,仅供参考。
代码:
#include <cstdio> #include <algorithm> #include <map> #include <vector> #include <string> #include <set> #include <cstring> using namespace std; const int N = 100010; int v[N]; map<int, int> mp; set<int> s; set<int>::iterator it, is, ir; int main() { int n, a, b; while( scanf("%d%d%d", &n, &a, &b) != EOF ) { int oo = 0; if(a > b) { swap(a, b); oo = 1; }; s.clear(); mp.clear(); for(int i = 0; i < n; i++) { scanf("%d", &v[i]); s.insert(v[i]); } int flag = 0; for(it = s.begin(); s.size() > 0; it = s.begin()) { int p1 = *it; is = s.find(a - p1); if(2 * p1 == a) { is = s.find(b - p1); if(is != s.end()) { s.erase(p1); s.erase(b - p1); mp[p1] = 1; mp[b - p1] = 1; } else { s.erase(p1); mp[p1] = 0; } } else if(2 * p1 == b){ s.erase(p1); mp[p1] = 1; }else if(is == s.end()) { is = s.find(b - p1); if(is == s.end()) { if(2 * p1 == b) { s.erase(p1); mp[p1] = 1; } else { flag = 1; break; } } else { s.erase(b - p1); s.erase(p1); mp[b - p1] = 1; mp[p1] = 1; } } else { is = s.find(b - p1); if(is == s.end()) { if(a - p1 == p1) { flag = 1; break; } s.erase(a - p1); s.erase(p1); mp[a - p1] = 0; mp[p1] = 0; } else { is = s.find(b - a + p1); if(is == s.end()) { s.erase(a - p1); s.erase(p1); mp[a - p1] = 0; mp[p1] = 0; } else{ s.erase(b - p1); s.erase(p1); mp[b - p1] = 1; mp[p1] = 1; s.erase(a - p1); s.erase(b - a + p1); mp[a - p1] = 1; mp[b - a + p1] = 1; } } } } if(flag == 1) printf("NO "); else { printf("YES "); for(int i = 0; i < n; i++) printf("%d%c", (mp[v[i]] ^ oo), (i == (n - 1))?' ':' '); } } return 0; }
C.Hack it!
题意:设f(x) = x % 10 + f(x / 10), f(0) = 0。给定n,现在希望找到一组l,r(l < r) 使得( f(l)+f(l+1)+...+f(r) ) % n = 0。
解法:我们考虑现在选择的区间为1-1000000,假设现在的sum % n = x。那么我把区间改为 2-1000001,答案显然会+1,因为f(1000001) - f(1) = 1,同理 f(1000000 + x) - f(x) = 1。所以我们可以通过把区间向右偏移n-x构造出答案。由于涉及到相乘爆long long我抄了个long long相乘的模板,当然也可以通过拆分乘的数然后每步取模来实现。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <set> 4 #include <algorithm> 5 using namespace std; 6 7 typedef long long ll; 8 typedef const long long cll; 9 10 ll mul_mod(ll a,ll b,cll &n){ 11 ll ans(0),tmp((a%n+n)%n); b=(b%n+n)%n; 12 while(b){ 13 if(b&1) if((ans+=tmp)>=n) ans-=n; 14 if((tmp<<=1)>=n) tmp-=n; 15 b>>=1; 16 } return ans; 17 } 18 int main() { 19 ll a; 20 scanf("%I64d", &a); 21 ll p = 1; 22 for(int i = 0; i < 19; i++) { 23 p = mul_mod(p, 10LL, a); 24 } 25 p = mul_mod(p, 900LL, a); 26 p += 1; 27 p %= a; 28 if(p) p = a - p; 29 printf("%I64d 10%019I64d ", p + 1, p); 30 31 return 0; 32 }