Codeforces #137 div2
2015-06-11 16:39:12
【传送门】
A题、B题签到。
C题:欧拉筛法
题意:给出 n 个数,它们的积为分子;再给出 m 个数,它们的积为分母。将这个分数约分之后输出,格式与输入一样。
思路:一开始的思路是对每个数 sqrt(n) 质因数分解,然后分别记录分子/分母质因子的数量,然后约分,但是TLE。
后来才知道,可以用欧拉筛法来线性处理出每个数的最小素因子(线性复杂度基于的是每个数只被最小素因子筛掉,所以每个数只被筛一次)
处理出每个数的最小素因子这个表后,对于分子的n个数和分母的m个数进行分解,记录下质因数的数量。然后
再对每个数分解一次,把能约分的质因数约掉即可。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) mkake_pair(a,b) #define PB(a) push_back(a) typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; const int MAXN = 10000010; int n,m,A,B; int tA[1000010],tB[1000010]; int c[MAXN],p[MAXN]; map<int,int> mp1,mp2; int f1[MAXN],f2[MAXN]; void Init(){ int cnt = 0; for(int i = 2; i < MAXN; ++i){ if(!c[i]) c[i] = p[cnt++] = i; for(int j = 0; j < cnt && i * p[j] < MAXN; ++j){ c[i * p[j]] = p[j]; if(i % p[j] == 0) break; } } } int main(){ Init(); scanf("%d%d",&n,&m); for(int i = 1; i <= n; ++i){ scanf("%d",&A); tA[i] = A; while(A > 1){ f1[c[A]]++; A /= c[A]; } } for(int i = 1; i <= m; ++i){ scanf("%d",&B); tB[i] = B; while(B > 1){ f2[c[B]]++; B /= c[B]; } } printf("%d %d\n",n,m); for(int i = 1; i <= n; ++i){ int res = tA[i]; while(tA[i] > 1){ if(f2[c[tA[i]]]){ f2[c[tA[i]]]--; res /= c[tA[i]]; } tA[i] /= c[tA[i]]; } printf("%d ",res); } puts(""); for(int i = 1; i <= m; ++i){ int res = tB[i]; while(tB[i] > 1){ if(f1[c[tB[i]]]){ f1[c[tB[i]]]--; res /= c[tB[i]]; } tB[i] /= c[tB[i]]; } printf("%d ",res); } puts(""); return 0; }
D题:sortings、two pointers
题意:给出两列长度一样的数列,代表 n 个人在两次比赛中的成绩,但是这两个数列的数并不是一一对应的,而是乱序的,也就是说每个人的总成绩是
两个数列中任意两个数的和(当然数字不能重复使用),Vasya 只知道自己的总成绩 >= x,问他的最高排名和最低排名可能是多少(总成绩一样的人排名
不确定,谁先谁后都有可能,但是互不相同)
思路:最高排名肯定是第一,考虑怎么算最低排名,其实这个问题就是计算最多有多少对数的和 >= x。
先考虑第一个数列中最大的数 max1,为了尽量合算,要在第二个数列中找到一个最小的数 t 且满足 max1+t >= x 这个条件。
然后考虑第一个数列中第二大、第三大的数....,处理方式与上同理。
这样我们就获得了一个算法,将两个数列排序,维护两个位置pointer,一个指向第一个数列最大数,一个指向第二个数列最小数
然后贪心地取,就获得了尽量多的总和 >= x 的数对。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB(a) push_back(a) typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; int n,x; int A[100010],B[100010]; int cnt[200010]; int main(){ scanf("%d%d",&n,&x); for(int i = 1; i <= n; ++i) scanf("%d",A + i); for(int i = 1; i <= n; ++i) scanf("%d",B + i); sort(A + 1,A + n + 1); sort(B + 1,B + n + 1,greater<int>()); int p2 = 1,ans = 0; for(int i = 1; i <= n; ++i){ if(A[i] + B[p2] < x){ continue; } else{ ++p2; ++ans; } } printf("1 %d\n",ans); return 0; }
E题:矩阵快速幂裸题
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB(a) push_back(a) typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; const ll mod = 1e9 + 7; ll n; int m,k; struct Mx{ ll a[52][52]; void clear(){ memset(a,0,sizeof(a)); } void stand(){ clear(); for(int i = 0; i < m; ++i) a[i][i] = 1; } Mx operator * (const Mx &b){ Mx c; c.clear(); for(int k = 0; k < m; ++k) for(int i = 0; i < m; ++i) for(int j = 0; j < m; ++j) c.a[i][j] = (c.a[i][j] + a[i][k] * b.a[k][j] % mod) % mod; return c; } }; int Idx(char c){ if(c >= 'a' && c <= 'z') return c - 'a'; return c - 'A' + 26; } Mx Q_pow(Mx t,ll y){ Mx res; res.stand(); while(y){ if(y & 1) res = res * t; t = t * t; y >>= 1; } return res; } int main(){ char s[10]; scanf("%I64d%d%d",&n,&m,&k); Mx t; for(int i = 0; i < m; ++i) for(int j = 0; j < m; ++j) t.a[i][j] = 1; for(int i = 1; i <= k; ++i){ scanf("%s",s); int a = Idx(s[0]),b = Idx(s[1]); t.a[b][a] = 0; } Mx ans; ans.clear(); for(int i = 0; i < m; ++i) ans.a[i][0] = 1; ans = Q_pow(t,n - 1) * ans; ll sum = 0; for(int i = 0; i < m; ++i) sum = (sum + ans.a[i][0]) % mod; printf("%I64d\n",sum); return 0; }