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;
}
View Code

 

 

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;
}
View Code

 

 

 

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;
}
View Code

 

posted @ 2015-06-11 18:07  Naturain  阅读(136)  评论(0编辑  收藏  举报