cf236,div2

B. Trees in a Row

暴力n^2可过,不过有个n的解法。

//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FD(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)

typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int maxn = 5010;

int a[maxn];
map<int, int>M;
int n, p;
int main ()
{
    int x, y;
    while (~RII(n, p))
    {
        M.clear();
        for (int i = 1; i <= n; i++) RI(a[i]);
        int ans = 0, ansx;
        for (int i = 1; i <= n; i++)
        {
            int x = a[i] - (i - 1) * p;
            if (x >= 1)
            {
                M[x]++;
                if (ans < M[x])
                {
                    ans = M[x];
                    ansx = x;
                }
            }
        }
        cout << n - ans << endl;
        int x = ansx;
        for (int i = 1; i <= n; i++)
        {
            int y = x - a[i];
            if (y > 0) printf("+ %d %d\n", i, y);
            else if (y < 0) printf("- %d %d\n", i, -y);
            x += p;
        }
    }
    return 0;
}

C. Searching for Graph

构造题。n个点要求2*n+p条边,且其有k点的子图不能超过2*k+p条边

关键是想到。每个点的度要>=2。(这种条件是不不完整的)正确的应该是,每个点至少对应不和其它点公用的不同的2条边。

或者先每个点按序构造两条边,再添加。其实直接按照1到n的顺序构造,也可保证正确。


注意:不能有重边和子环。

//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FD(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)

typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int MAXN = 1000010;


int main ()
{
    int n, p;
    int T;
    RI(T);
    while(T--)
    {
        RII(n, p);
        int x = p / n;
        int y = p % n;
        for (int i = 0; i < n; i++)
        {
            int up = i + x + 2;
            if (y) up++, y--;
            if (up >= n)
            {
                for (int j = i + 1; j < n; j++)
                printf("%d %d\n", i + 1, j + 1);
                for (int j = 0; j <= up % n; j++)
                printf("%d %d\n", i + 1, j + 1);
            }
            else
            {
                for (int j = i + 1; j <= up; j++)
                printf("%d %d\n", i + 1, j + 1);
            }
        }
    }
    return 0;
}

D. Upgrading Array

题目有下2种做法,其实实质是相同的。

第1个解法的效率高些,但第二个解法写起来更加的简单。第一种解法,其实是对每个前缀序列的最大gcd进行了,细节分析,确定操作后对解的影响值记为get(gcd);其实没必要这么做,

从第2个解法可以看出,只要知道要处理的前缀序列的最大gcd,就可一比较简单的计算出操作后对解的影响get(gcd)。


再对序列进行操作时,倒着操作可保证最优:

因为操作的区间是[1, r],且操作区间每个数除以[1,r]的区间求最大gcd。

大区间的gcd值受小区间的影响,且小区间处理后,大区间就没有办法处理,所以如果有多个操作,则一定是按照大区间到小区间的操作顺序。

具体处理:对每个[1,r]的区间求最大gcd,保存在gc[]中,则gc[i - i] >= gc[i],且实际上gc[i]是gc[i - 1]的因子。

(1)如果get(gc[i])> 0;则不应当对其操作,倒着处理时,对区间[1,i]不操作。对于区间[1, i - 1]的操作与否,再进行判断。

(2)如果get(gc[i])<0;则应当对其操作,倒着处理时,对区间[1,i]不操作。


自己的解法:

//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FD(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)

typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int maxn = 5010;

vector<int>t, a, b, c;
int ans;
set<int>S;
int n, m;
void get_sum()
{
    for (int r = 0; r < a.size(); r++)
    {
        int x = a[r];
        for (int i = 2; i * i <= x; i++)
        {
            while (x % i == 0)
            {
                x /= i;
                if (S.find(i) == S.end()) ans++;
                else ans--;
            }
        }
        if (x != 1)
        {
            if (S.find(x) == S.end()) ans++;
            else ans--;
        }
    }
    return ;
}
void get_t(vector<int> b, int val)
{
    for (int r = 0; r < b.size(); r++)
    {
        int x = b[r], num = 0, nownum;
        int y = a[0];
        while (y % x == 0)
        {
            y /= x;
            num++;
        }
        if(!num) continue;
        for (int i = 1; i < a.size(); i++)
        {
            y = a[i];
            nownum = 0;
            while (y % x == 0)
            {
                nownum++;
                y /= x;
            }
            nownum = min(nownum, num);
            if (nownum < num)
            {
                t[i - 1] += val * (num - nownum);
                num = nownum;
            }
        }
        t[a.size() - 1] += val * num;///!!!

    }
}
void solve()
{
    for (int r = n - 1; r >= 0; r--)
    {
        if (t[r] < 0)
            ans -= (r + 1) * t[r];
        else if (r)///!!!!
            t[r - 1] += t[r];
    }
}

int main ()
{
    int x, y;
    S.clear();
    ans = 0;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        RI(x);
        a.push_back(x);
        t.push_back(0);
    }
    for (int i = 1; i <= m; i++)
    {
        RI(x);
        b.push_back(x);
        S.insert(x);
    }
    x = a[0];
    for (int i = 2; i * i <= x; i++)
    {
        if (x % i == 0)
        {
            if (S.find(i) == S.end())
                c.push_back(i);
            while (x % i == 0)
                x /= i;
        }
    }
    if (x != 1 && S.find(x) == S.end()) c.push_back(x);

    get_sum();
    get_t(b, -1);
    get_t(c, 1);
    solve();
    cout << ans << endl;
    return 0;
}
参考他人的做法:

//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)
typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int maxn = 5010;

int gc[maxn], a[maxn];
set<int>S;
int n, m;
int get(int x)
{
    int ret = 0;
    for (int i = 2; i * i <= x; i++)
    {
        while (x % i == 0)
        {
            x /= i;
            if (S.find(i) == S.end()) ret++;
            else ret--;
        }
    }
    if (x > 1)
    {
        if (S.find(x) == S.end()) ret++;
        else ret--;
    }
    return ret;
}

int solve()
{
    int ans = 0;
    for (int i = 1; i <= n; i++)
        ans += get(a[i]);
    int com_gcd = 1;
    for (int i = n; i >= 1; i--)
    {
        int z = get(gc[i] / com_gcd);
        if (z < 0)
        {
            ans -= z * i;
            com_gcd *= (gc[i] / com_gcd);
        }
    }
    return ans;
}

int main ()
{
    int x, y;
    S.clear();
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        RI(a[i]);
    for (int i = 1; i <= m; i++)
    {
        RI(x); S.insert(x);
    }
    gc[1] = a[1];
    for (int i = 2; i <= n; i++) gc[i] = __gcd(gc[i - 1], a[i]);

    cout << solve() << endl;
    return 0;
}

E. Strictly Positive Matrix

...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值