Codeforces Round332 部分题解

A. Patrick and Shopping
应用Floyd-Warshall的想法,先把每两点之间的最短距离更新了,然后最后的结果就是d1 + d2 + d3

#define FOR(a, b, n) for(int (a) = (b); (a) < (n); ++(a))
#define ITE(a, v) for(auto (a) = v.begin(); (a) != v.end(); ++(a))
#define LL long long
#define ALL(v) v.begin(),v.end()
#define ZERO(v) memset(v, 0, sizeof v)
#define NEG(v)  memset(v, -1, sizeof v)
#define F first
#define S second
#define PB push_back
#define MP make_pair
#define MOD 1000000007
#define PI 3.141592653589793
#define INF 5e8
inline long double min(long double a , long double b) {if(a < b)return a; return b;}
inline long double max(long double a , long double b) {if(a < b)return b; return a;}


int d1,d2,d3;
int  main()
{

    cin >> d1 >> d2 >> d3;
    d3 = min(d1 + d2, d3);
    d1 = min(d2 + d3, d1);
    d2 = min(d1 + d3, d2);
    cout << d1 + d2 + d3 << endl;
    return 0;

}

B. Spongebob and Joke
题很简单,题意很复杂的典型。。
大意就是A是一个长度m的数组,值得范围[1,n],F是长度n的数组,B也是长度n的数组,对于B有B(i) = F(A(i)),现在已知B,F,求A的解的情况。
因为F中的值范围也是[1,n],先建立一个数组将F中每个值对应的index记录一下,比如说如果F是[1,2,2],那么record[1] = {0}, record[2] = {1,2},record[3] = {}. 然后遍历B,对于每个B值,找到其对应的index,如果数量超过一个,那么肯定有ambiguity,如果数量是0,那么不可能啦,如果数量是1,继续check下一个,复杂度O(n)

#define FOR(a, b, n) for(int (a) = (b); (a) < (n); ++(a))
#define ITE(a, v) for(auto (a) = v.begin(); (a) != v.end(); ++(a))
#define LL long long
#define ALL(v) v.begin(),v.end()
#define ZERO(v) memset(v, 0, sizeof v)
#define NEG(v)  memset(v, -1, sizeof v)
#define F first
#define S second
#define PB push_back
#define MP make_pair
#define MOD 1000000007
#define PI 3.141592653589793
#define INF 5e8
inline long double min(long double a , long double b) {if(a < b)return a; return b;}
inline long double max(long double a , long double b) {if(a < b)return b; return a;}


int n;
int m;
int b[100100];
int f[100100];
vector<int> pos[100100];
vector<int> res;
int solve()
{

    bool flag = true;
    FOR(i,0,m)
    {
        int val = b[i];
        if(pos[val].size() > 1)
        {
            flag = false;
        }
        else if(pos[val].size() == 0)
        {
            return -1;
        }
        else
            res.PB(pos[val][0]);

    }
    if(flag == false)
        return 0;
    return 1;

}
int  main()
{

    cin >> n;
    cin >> m;
    FOR(i,0,n)
    scanf("%d", &f[i]);
    FOR(i,0,m)
    scanf("%d", &b[i]);
    FOR(i,0,n)
    {
        pos[f[i]].PB(i);
    }
    int ress = solve();
    if(ress == 1)
    {
        cout << "Possible" << endl;
        FOR(i,0, res.size())
        cout << res[i]  + 1<< " ";
        cout << endl;
    }
    else if(ress ==0)
        cout << "Ambiguity" << endl;
    else
        cout <<"Impossible" << endl;
    return 0;
}

C. Day at the Beach
这道题卡了挺久。。。但是真的不难
题意大概是讲将一个unsorted array 分成几部分,如果将每部分sort以后总的array是sorted的话,那么这个分块就是合理的,问最大的合理的分块是多少。
一开始我打算二分然后验证分块是否合理,最后发现思路和直接解是一样的。
当前块的最小值一定大于前一块的最大值,基于此推导的话一定是大于前面的块的所有的数。那么当前块的最大值一定是大于之前的所有的数的,而且是小于后面的块的最小值。
那么我们找可能的最大值就行,最大值的条件是大于之前所有的数,他覆盖的范围是直到后面的数的最小值大于它。
所以用prefix[i]记录前i 个数的最大值,suffix[i]记录从i开始后面的数的最小值。找到一个数发现他是最大值以后就不断向后找,直到suffx[i] 大于这个最大值。不过我发现直接找prefix[i] <= suffix[i] 和之前的算法等价。

#define FOR(a, b, n) for(int (a) = (b); (a) < (n); ++(a))
#define ITE(a, v) for(auto (a) = v.begin(); (a) != v.end(); ++(a))
#define LL long long
#define ALL(v) v.begin(),v.end()
#define ZERO(v) memset(v, 0, sizeof v)
#define NEG(v)  memset(v, -1, sizeof v)
#define F first
#define S second
#define PB push_back
#define MP make_pair
#define MOD 1000000007
#define PI 3.141592653589793
#define INF 5e8
inline long double min(long double a , long double b) {if(a < b)return a; return b;}
inline long double max(long double a , long double b) {if(a < b)return b; return a;}


int n;
int a[100100];
int pref[100100];
int suff[100100];
int solve()
{
    pref[0] = a[0];
    suff[n - 1] = a[n - 1];
    FOR(i,1,n)
    pref[i] = max(pref[i - 1], a[i]);
    for(int i = n - 2; i >= 0; i--)
        suff[i] = min(suff[i + 1], a[i]);
    int count = 0;
    FOR(i,0,n - 1)
        if(pref[i] <= suff[i + 1])
            count++;
    count++;
    return count;
}
int  main()
{

    cin >> n;
    FOR(i,0,n)
    {
        scanf("%d", &a[i]);
    }
    cout << solve() << endl;
    return 0;

}

D. Spongebob and Squares
感觉C,D应该换一下难度才对
大意就是对于m*n的一个矩阵,里面包含的长度为1,2,3…min(m,n)的正方体矩阵个数为x个,现在已知x,求可能的m,n。
纯数学问题,如果m,n已知,假设m < n, 那么x = m * n + (m - 1) * (n - 1) + (m - 2) * (n - 2) +… + 1 * (n - m + 1)
设diff = n - m, 那么x = 1 * (diff + 1) + 2 * (diff + 2) + … + m * (diff + m) = diff * (m + 1) * m / 2 + (m + 1)(m + 2)(2m + 1) / 6
因为 x <= 1e18,所以m最多等于1e6, 从1开始遍历m就行,如果存在合理的diff的值,则记录n = diff + m
记着每次要insert pair(m,n)和pair(n,m)
我用set存得,所以复杂度O(NlgN), N = 1e6,不过应该优化到O(N)是可以的

#define FOR(a, b, n) for(int (a) = (b); (a) < (n); ++(a))
#define ITE(a, v) for(auto (a) = v.begin(); (a) != v.end(); ++(a))
#define LL long long
#define ALL(v) v.begin(),v.end()
#define ZERO(v) memset(v, 0, sizeof v)
#define NEG(v)  memset(v, -1, sizeof v)
#define F first
#define S second
#define PB push_back
#define MP make_pair
#define MOD 1000000007
#define PI 3.141592653589793
#define INF 5e8
inline long double min(long double a , long double b) {if(a < b)return a; return b;}
inline long double max(long double a , long double b) {if(a < b)return b; return a;}


LL x;
set<pair<LL,LL> > res;
LL calc(int k)
{
    LL res = 1;
    res *= k;
    res *= (k + 1);
    res *= (2*k + 1);
    res /= 6;
    return res;
}
void solve()
{
    for(int k = 1; k <= 1e6 + 1 && calc(k) <= x; k++)
    {
        LL temp = x - calc(k);
        LL temp1 = 1LL * k * (k + 1) / 2;
        if(temp % temp1 == 0)
        {
            LL temp2 = temp / temp1;
            res.insert(MP(k,k + temp2));
            res.insert(MP(k + temp2, k));
        }
    }
}
int  main()
{

    cin >> x;
    solve();
    cout << res.size() << endl;
    ITE(i,res)
    cout << i->first << " " << i->second << endl;
    return 0;

}

E. Sandy and Nuts
还没做,每次都要填不完E的大坑啊。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章