csuoj 2015.3.15

自己模拟,水过三题。

最近做题总是这种,题解一看就懂了的情况。

感觉自己已经不会思考了,五月病。什么都不想做,事情又多,自己又蠢,练习的效果感觉差强人意。

比赛地址:http://acm.csu.edu.cn/OnlineJudge/contest.php?cid=2069


F:

题意:

给三个数n,a,b,且s = (1 << n) = a + b,现在一天可以把s或者s‘对分成一半,以此类推,问第几天能满足分成的两堆一个为a,一个为b。


解析:

我不会说我因为LLwa了几发。。。脑子真是糊死了。

把a和b中小的那个化为二进制数,他二进制为1的最低位就是所要求得时间,因为最低位出现说明之前的位置的数已经被平分过,凑和直接凑就行了。

详见代码。


代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 100 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);


int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        int n;
        LL a, b;
        scanf("%d%lld%lld", &n, &a, &b);
        if (a > b)
        {
            LL t = a;
            a = b;
            b = t;
        }
        int cnt = 0;
        while (a)
        {
            if (a & 1)
                break;
            cnt++;
            a >>= 1;
        }
        printf("%d\n", n - cnt);
    }
    return 0;
}


K:

因为刚开始卡了F题,丢人,看榜我开始做k,k题G友比这场的时候有叫我看,我当时没有推出来。

然后那天做的时候推啊推的就推出来了。

题意:

有n个pizza,他们是按照卡路里从小到大排的,给一个你想吃的号码k。

现在有三个人,按照卡路里大,卡路里小,你选择的顺序来否决pizza,问你耍点心机,能不能吃到你想吃的号码pizza。


解析:

往有规律的方向想,把1-8的情况列出来,反正是脑子不灵光:

1 YES


1 YES

2 NO


1 NO

2 YES

3 NO


1 NO

2 YES

3 YES

4 NO


1 NO

2 YES

3 YES

4 NO

5 NO


1 NO

2 NO

3 YES

4 YES

5 NO

6 NO


1 NO

2 NO

3 YES

4 YES

5 YES

6 NO

7 NO


1 NO

2 NO

3 YES

4 YES

5 YES

6 NO

7 NO

8 NO

然后去找规律,发现YES的起始刚好是n / 3,YES的个数刚好是 ceil((n - 1) / 3), 所以问题就引刃而解了。

感觉这种方法对于比较蠢的人,such as me,挺好用的!!上次那题dp也是!


代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 100 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);


int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int ncase;
    int n, p;
    while (~scanf("%d%d", &n, &p))
    {
        for (int i = 0; i < n; i++)
        {
            int x;
            char s[110];
            scanf("%d %s", &x, s);
        }
        int lo = n / 3 + 1;
        int hi = lo + ceil((n - 1)/ 3);
//        cout << lo << hi << endl;
        if (lo <= p && p <= hi)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}


A:

做A题的感觉很像上次做哈理工的校赛那道调和级数数学题的感觉,反正题目看不懂。

题意:

求 a[a[i]] = a[i] 的个数。


解析:

刚开始的反应,置换群!然后大脑就空白了。

然后试了下n! 发现-1就行了。黑线。。。


代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 2000000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

LL pow_mod(LL a, LL n, LL mod)
{
    if (n == 0)
        return 1;
    LL x = pow_mod(a, n >> 1, mod);
    LL res = x * x % mod;
    if (n % 2)
        res = res * a % mod;
    return res;
}

LL fun(LL n)
{
    LL res = 1;
    for(int i = 1; i <= n; i++)
    {
        res = (res * i) % 1000000007;
    }
    return res;
}

int main()
{
#ifdef LOCAL
  //  freopen("in.txt", "r", stdin);
#endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        LL n;
        scanf("%lld", &n);
        printf("%lld\n", fun(n) - 1);
    }
    return 0;
}

然后是看完题解就懂自己蠢了的E:

题意:

给一串n个数字,这n个数字组成一个圈,然后你来选择起点终点,使得连续的一段是最大的。

即圈圈最大连续字段和。


解析:

加上了一个可以跨越最后一个元素回到首元素的条件,就多上了一种情况。

首先,第一种情况是普通的最大连续字段和,直接解,得一个值;

然后,第二种情况是可以回首元素的字段和,怎么处理呢,很简单,整个段的和,挖空中间一段就模拟了从尾元素回到首元素的情形。

具体实现:先把全段和记录下来,然后把所有元素取负,变为相反数,然后再找一遍,找最大连续字段和最大,即反回去是加回去,然后比较两值大小就行了。


代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 1000000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

LL a[maxn];

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        memset(a, 0, sizeof(a));
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
        {
            scanf("%lld", &a[i]);
        }
        LL thisSum = 0;
        LL sum1 = 0;
        LL ans1 = 0;
        for (int i = 0; i < n; i++)
        {
            thisSum += a[i];
            sum1 += a[i];
            if (thisSum < 0)
            {
                thisSum = 0;
            }
            if (ans1 < thisSum)
            {
                ans1 = thisSum;
            }
            a[i] = -a[i];
        }
        LL sum2 = 0;
        LL ans2 = 0;
        for (int i = 0; i < n; i++)
        {
            sum2 += a[i];
            if (sum2 < 0)
            {
                sum2 = 0;
            }
            if (ans2 < sum2)
            {
                ans2 = sum2;
            }
        }
        //printf("%lld %lld %lld\n", sum1, ans1, ans2);
        printf("%lld\n", max(ans1, sum1 + ans2));
    }
    return 0;
}

G:

G是二分图最大匹配啊,二分图最大匹配啊,裸的二分图最大匹配啊啊啊!

当时不是学的好好的嘛- -。

题意:

给矩阵n*m上的k个double点,选一个横坐标或者纵坐标来击穿x轴或者y轴,问最小的射击次数。


解析:

最小点覆盖等于二分图最大匹配。

匈牙利算法。

把double的 x 和 y 直接向下取整就ok了。


代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 10000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int fr[maxn];
bool vis[maxn];
vector<int> g[maxn];
int n, m, k;

bool match(int v)
{
    for (int i = 0; i < g[v].size(); i++)
    {
        int u = g[v][i];
        if (!vis[u])
        {
            vis[u] = true;
            if (fr[u] == -1 || match(fr[u]))
            {
                fr[u] = v;
                return true;
            }
        }
    }
    return false;
}

int hungary()
{
    int ret = 0;
    memset(fr, -1, sizeof(fr));
    for (int i = 0; i < k; i++)
    {
        memset(vis, false, sizeof(vis));
        if (match(i))
            ret++;
    }
    return ret;
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        scanf("%d%d%d", &n, &m, &k);
        for (int i = 0; i < k; i++)
        {
            g[i].clear();
        }
        for (int i = 0; i < k; i++)
        {
            double x, y;
            scanf("%lf%lf", &x, &y);
            int X = x;
            int Y = y;
            g[X].push_back(Y);
        }
        printf("%d\n", hungary());
    }
    return 0;
}


C:

新学了一种dp,双调旅行商。

题意:

题意的描述就是双调旅行商的定义啦,这种旅程即为从最左点开始,严格地从左到右直至最右点,然后严格地从右到左直至出发点。


解析:

具体解析放到下一题去讲。


代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 520;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

struct Node
{
    double x, y;
} node[maxn];

int n;
double dp[maxn][maxn];

bool cmp(Node a, Node b)
{
    return a.x < b.x;
}

double dist(Node a, Node b)
{
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

double DP()
{
    dp[1][2] = dist(node[1], node[2]);
    for (int j = 3; j <= n; j++)
    {
        //i < j - 1
        for (int i = 1; i < j - 1; i++)
        {
            dp[i][j] = dp[i][j - 1] + dist(node[j - 1], node[j]);
        }
        // i = j - 1
        dp[j - 1][j] = inf;
        for (int k = 1; k < j - 1; k++)
        {
            double t = dp[k][j - 1] + dist(node[k], node[j]);
            if (t < dp[j - 1][j])
            {
                dp[j - 1][j] = t;
            }
        }
    }
    return dp[n - 1][n] + dist(node[n - 1], node[n]);
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
        {
            scanf("%lf%lf", &node[i].x, &node[i].y);
        }
        sort(node + 1, node + n + 1, cmp);
        printf("%.3lf\n", DP());
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值