Codeforces Round #257 (Div. 2)

OpenSoucre發表於2014-07-20

A - Jzzhu and Children

找到最大的ceil(ai/m)即可

#include <iostream>
#include <cmath>
using namespace std;

int main(){
    int n,m;
    cin >> n >> m;
    double a, maxv = 0;
    int maxIdx = 0;
    for(int i = 0; i < n; ++ i){
        cin >> a;
        if(maxv <= ceil(a/m)){
            maxv = ceil(a/m);
            maxIdx = i+1;
        }
    }
    cout<<maxIdx<<endl;


}
View Code

B - Jzzhu and Sequences

f= fi-1-fi-2

f1=x, f2=y, f3=y-x, f4 = y-x-y = -x, f5 = -x-(y-x) = -y , f6 =-y-(-x) = x-y

f7 = x-y-(-y)=x, f8 = x-(x-y) = y...........

注意該序列的迴圈節是6

只要算出前六個數即可。

#include <iostream>
#include <vector>
#define ll long long
#define MOD 1000000007
using namespace std;

int main(){
    ll x,y,n;
    cin >> x >> y >> n;
    vector<ll> f(6,0);
    f[0] =x;f[1]=y;
    for(int i = 2; i < 6; ++ i) f[i] = f[i-1]-f[i-2];
    cout<<(f[(n-1)%6]%MOD+MOD)%MOD<<endl;
}
利用迴圈節

本題也可以採用矩陣快速冪運算

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <queue>
#include <utility>
#define ll long long
#define MOD 1000000007
using namespace std;


struct matrix
{
    ll m[2][2];
}ans, base;

matrix multi(matrix a, matrix b)
{
    matrix tmp;
    for(int i = 0; i < 2; ++i)
    {
        for(int j = 0; j < 2; ++j)
        {
            tmp.m[i][j] = 0;
            for(int k = 0; k < 2; ++k)
                tmp.m[i][j] = (tmp.m[i][j] + a.m[i][k] * b.m[k][j]);
        }
    }
    return tmp;
}
ll fast_mod(ll n,ll x,ll y)
{
    base.m[0][0] = 1;
    base.m[0][1] = -1;
    base.m[1][0] = 1;
    base.m[1][1] = 0;
    ans.m[0][0] = ans.m[1][1] = 1;
    ans.m[0][1] = ans.m[1][0] = 0;
    while(n)
    {
        if(n & 1)
        {
            ans = multi(ans, base);
        }
        base = multi(base, base);
        n >>= 1;
    }

    return ans.m[0][0]*y+ans.m[0][1]*x;
}

int main(){
    ll x,y,n;
    cin >> x >> y >> n;
    ll res = 0;
    if(n == 1) res = x;
    else if(n == 2) res = y;
    else res = fast_mod(n-2,x,y);
    if(res < 0) res = res%MOD;
    cout<<(res+MOD)%MOD<<endl;
}
矩陣快速冪運算

注意結果輸出時對負數要 (res%mod+mod)%mod,因為res可能大於mod, 不然結果可能被cha掉

C - Jzzhu and Chocolate

題目的意思:

  給nxm的巧克力,切k刀後,求最小塊巧克力的最大面積

解題思路:

  可以假設n<m,如果n>m,則交換n和m。

  現在將行分成x行,列分成y列,相當於行切x-1次,列切y-1次,x-1+y-1=k 即x+y=k-2,

  此時最小塊面積是floor(n/x)*floor(m/y),要使最小塊面積最大,即使x*y儘量小。

  x*y=x(k-2-x) = -x2+(k-2)x,這是一個開頭向下的拋物線,拋物線中間值最大,要是值x*y最小,x必須在拋物線的兩邊,x在0這邊或者k這邊。

  現在分情況考慮

  (1)如果k<n,這最優的(x,y),是{x=1,y=k+1}(列切k次)或者{x=k+1, y=1}(行切k次)

  (2)如果n≤k<m,這最優的(x,y),是{x=1,y=k+1}(列切k次)

  (3)如果m≤k≤n+m-2,最優的(x,y),是{x=k+2-m,y=m}(行切k+1-m次,列切m次)

  (4) 如果 k>n+m-2,則不存在切割方法(行最多切n-1次,列最多切m-1次)

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#define ll long long
using namespace std;

int main(){
    ll n,m,k;
    cin >> n >> m >>k;
    if(n > m) swap(n,m);
    if(k < n) cout<<max(n*(m/(k+1)),n/(k+1)*m)<<endl;
    else if(k>=n && k < m) cout<<n*(m/(k+1))<<endl;
    else if(k>=m && k <= n+m-2) cout<<n/(k+2-m)<<endl;
    else cout<<-1<<endl;
}
View Code

D - Jzzhu and Cities

題目的意思:

  給你n個城市,m條無向有權邊,然後還有k條邊,每條邊是從起點出發到i,以及相應的權重,刪除這k條邊中的一些邊,使每個點到起點的最短距離不變。

解題思路是:

  將原有的m條邊和k條邊都加入圖中,注意要區分這兩種不同的邊,對於k條邊是可以刪除的,要進行標記。然後跑一遍dijkstra演算法,記錄其每個點最短路徑的前一個點。然後遍歷這些點,如果前一個點是起始點,且當前點到前一個點是可以刪除邊,則這條邊不可以刪除。

  關於dijkstra演算法,可以參考《演算法競賽入門經典訓練指南》p327給的模板,這本書上面有很多模板寫的比較好

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <cstring>
#include <cstdlib>
#define ll long long
#define INF 0xffffffff
#define maxn 100000
using namespace std;

struct Edge{
    int from,to;
    ll dist;
    bool flag;
};

struct HeapNode{
    ll d;
    int u;
    bool operator<(const HeapNode& rhs) const{
        return d > rhs.d;
    }
};

struct Dijkstra{
    int n,m;
    vector<Edge> edges;
    vector<int> G[maxn];
    bool done[maxn];
    ll d[maxn];
    int p[maxn];

    void init(int n){
        this->n = n;
        for(int i = 0; i < n ; ++ i) G[i].clear();
        edges.clear();
    }

    void AddEdge(int from, int to, int dist,bool flag = false){
        edges.push_back((Edge){from,to,dist,flag});
        m = edges.size();
        G[from].push_back(m-1);
    }

    void dijkstra(int s){
        priority_queue<HeapNode> Q;
        for(int i = 0 ; i < n; ++ i ) d[i] = INF;
        d[s] = 0;
        memset(done,0,sizeof(done));
        Q.push((HeapNode){0,s});
        while(!Q.empty()){
            HeapNode x = Q.top();Q.pop();
            int u = x.u;
            if(done[u]) continue;
            done[u] = true;
            for(int i = 0 ; i < G[u].size(); ++ i){
                Edge& e = edges[G[u][i]];
                if(d[e.to] > d[u] + e.dist || (d[e.to] == d[u] + e.dist && !e.flag)){
                    d[e.to] = d[u] + e.dist;
                    p[e.to] = G[u][i];
                    Q.push((HeapNode){d[e.to], e.to});
                }
            }
        }
    }
};

int main(){
    int n,m,k;
    cin >> n >> m >> k;
    Dijkstra a;
    a.init(n);
    for(int i = 0 ; i < m; ++ i){
        int u,v;
        ll x;
        cin >> u >> v >>x;
        --u;--v;
        a.AddEdge(u,v,x);
        a.AddEdge(v,u,x);
    }
    for(int i = 0 ; i < k; ++i){
        int s;
        ll y;
        cin >>s >> y;
        --s;
        a.AddEdge(0,s,y,true);
        a.AddEdge(s,0,y,true);
    }
    a.dijkstra(0);
    int res = 0;
    for(int i = 1; i < n; ++ i){
        if(a.edges[a.p[i]].flag) res++;
    }
    cout<<k-res<<endl;
}
Dijkstra演算法

E - Jzzhu and Apples

題目的意思:

  有1到n個數,它們兩兩分為一組,要求在一組的數字的公共因子大於1,即要求這兩個數不互質,問最多有多少分組

解題思路:

  對於找出n以內的素數,由於n的最大為100000,可以考慮用篩選法選擇素數。(其核心思想就是素數的倍數都不是素數)

  2是素數,則2*2,2*3........都不是素數,然後將這些數標記,下一個數是3

  3是素數,則3*2,3*3........都不是素數,然後將這些數標記,下一個數是5

  .........

  對於1和大於n/2的素數不可能滿足要求,因為不可能存在一個在n內的數和大於n/2的素數有公因子

  只需要考慮2到n/2範圍內的素數。這裡可能有疑問,為什麼不考慮2到n/2的非素數?可以想象把篩選法篩選素數的方法逆過來。

  假設i是2~n/2內的一個素數,那麼2*i,3*i,4*i......(小於等於n),有公因子i,

    如果這些數的個數(包括i)為偶數的話,那麼這些數兩兩組合即可

    否則為奇數的話,選擇2*i(i的偶數倍都可以),留給2的倍數去考慮,然後其餘的兩兩組合

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <utility>
#define  MAX (100000+5)
using namespace std;

bool prime[MAX], visit[MAX];
void init(){
    memset(prime,true,sizeof(prime));
    memset(visit,false,sizeof(visit));
    for(int i = 2; i < MAX;++i){
        if(prime[i]){
            for(int j = i*2;j < MAX; j+=i) prime[j] = false;
        }
    }
}

int main(){
    init();
    int n;
    cin >>n;
    vector<pair<int,int> >res;
    for(int i = n/2; i>=2; -- i){
        if(prime[i]){
            vector<int> divisor;
            for(int j = i; j <= n; j+=i){
                if(!visit[j]) divisor.push_back(j);
            }
            if(divisor.size()%2 != 0){
                for(int j = 0 ; j < divisor.size(); ++ j){
                    if(divisor[j]%2 == 0) {
                        swap(divisor[j],divisor.back());
                        divisor.pop_back();
                        break;
                    }
                }
            }
            for(int j = 0; j < divisor.size() ; j+=2){
                res.push_back(make_pair(divisor[j],divisor[j+1]));
                visit[divisor[j]] = true;
                visit[divisor[j+1]] = true;
            }
        }
    }
    cout<<res.size()<<endl;
    for(int i = 0 ; i < res.size(); ++i ) cout<<res[i].first<<" "<<res[i].second<<endl;
}
View Code

相關文章