2014多校联合十(HDU 4972 HDU 4973 HDU 4974 HDU 4975)

HDU 4972 A simple dynamic programming problem

题意:篮球比赛有1、2、3分球  现给出两队的分差序列(5:3 分差2  3:5分差也是2)  问有多少种可能的比分

思路:

比较简单的想法题  可以类一张表“从分差x到分差y一共有几种情况”  很容易发现只有1->2和2->1的时候会多一种情况  其他均是一种  所以只需要统计这种特殊分差即可  注意一下最后结果要不要乘2  如果最后分差是0就不用因为x:x只有一种  但是最后分差不是0就要乘  因为x:y和y:x算两种  还有本题有坑!! 那个SB记分员会把分数记错  所以一旦记错种类数就为0了

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

int a[100010];

int main()
{
    int t,n,i,l,flag,cas=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++) scanf("%d",&a[i]);
        a[0]=0;
        l=1;
        flag=1;
        for(i=1;i<=n;i++)
        {
            if(abs(a[i]-a[i-1])>3||(a[i]!=1&&a[i]==a[i-1]))
            {
                flag=0;
                break;
            }
            if(a[i-1]==1&&a[i]==2||a[i-1]==2&&a[i]==1) l++;
        }
        printf("Case #%d: ",cas++);
        if(!flag)
        {
            printf("0\n");
        }
        else
        {
            if(a[n]==0)
                printf("%d\n",l);
            else printf("%d\n",l*2);
        }
    }
    return 0;
}

HDU 4973 A simple simulation problem

题意:一段区间一开始是1、2、3…n  有m个操作  D操作为区间复制  Q为查询区间最多的相同元素个数

思路:

一看就是线段树…  由于区间会复制  所以自然会想到节点记得是元素个数  比较有意思的是寻找区间方式和以往不同  不过既然已经记录了元素个数  我们就可以按个数来寻找了  我是用(head,num)表示该区间从第head个元素开始操作num个元素  这样就可以实现在线段树上找区间了  注意的是叶子节点特殊处理一下就好

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef __int64 LL;
#define N 50010
#define L(x) (x<<1)
#define R(x) ((x<<1)|1)

struct node
{
    LL sum,max,lazy;
    bool leaf;
}f[N*4];
int t,n,m;

void up(int i)
{
    f[i].sum=f[L(i)].sum+f[R(i)].sum;
    f[i].max=max(f[L(i)].max,f[R(i)].max);
}

void down(int i)
{
    if(f[i].lazy!=1)
    {
        f[L(i)].sum*=f[i].lazy;
        f[L(i)].max*=f[i].lazy;
        f[L(i)].lazy*=f[i].lazy;
        f[R(i)].sum*=f[i].lazy;
        f[R(i)].max*=f[i].lazy;
        f[R(i)].lazy*=f[i].lazy;
        f[i].lazy=1;
    }
}

void init(int l,int r,int i)
{
    f[i].leaf=false;
    f[i].lazy=1;
    if(l==r)
    {
        f[i].leaf=true;
        f[i].sum=f[i].max=1;
        return ;
    }
    int mid=(l+r)>>1;
    init(l,mid,L(i));
    init(mid+1,r,R(i));
    up(i);
}

void update(LL head,LL num,int i)
{
    if(head==1&&num==f[i].sum)
    {
        f[i].sum*=2;
        f[i].max*=2;
        f[i].lazy*=2;
        return ;
    }
    if(f[i].leaf)
    {
        f[i].sum+=num;
        f[i].max+=num;
        return ;
    }
    down(i);
    if(f[L(i)].sum>=head+num-1) update(head,num,L(i));
    else if(head>f[L(i)].sum) update(head-f[L(i)].sum,num,R(i));
    else
    {
        LL fzc=f[L(i)].sum-head+1;
        update(head,fzc,L(i));
        update(1,num-fzc,R(i));
    }
    up(i);
}

LL query(LL head,LL num,int i)
{
    if(head==1&&num==f[i].sum) return f[i].max;
    if(f[i].leaf) return num;
    down(i);
    LL res;
    if(f[L(i)].sum>=head+num-1) res=query(head,num,L(i));
    else if(head>f[L(i)].sum) res=query(head-f[L(i)].sum,num,R(i));
    else
    {
        LL fzc=f[L(i)].sum-head+1;
        res=query(head,fzc,L(i));
        res=max(res,query(1,num-fzc,R(i)));
    }
    up(i);
    return res;
}

int main()
{
    int i,cas=1;
    LL l,r;
    char op[3];
    scanf("%d",&t);
    while(t--)
    {
        printf("Case #%d:\n",cas++);
        scanf("%d%d",&n,&m);
        init(1,n,1);
        while(m--)
        {
            scanf("%s%I64d%I64d",op,&l,&r);
            if(op[0]=='D') update(l,r-l+1,1);
            else printf("%I64d\n",query(l,r-l+1,1));
        }
    }
    return 0;
}

HDU 4974 A simple water problem

题意:你可以每次选1个或2个元素使它们+1  问  最少几次操作能从全0加到给出的序列

思路:

一开始一定2个加一次  如果最后只剩下一个就只能1个加一次  所以特判一下最大的元素会不会超过其他元素的和

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef __int64 LL;

LL a,b,c,ans;
int T,t,n;

int main()
{
    int i;
    scanf("%d",&T);
    for(t=1;t<=T;t++)
    {
        scanf("%d",&n);
        a=b=c=0;
        for(i=1;i<=n;i++)
        {
            scanf("%I64d",&a);
            c=max(c,a);
            b+=a;
        }
        a=b-c;
        if(c>=a) ans=c;
        else
        {
            ans=b/2;
            if(ans*2<b) ans++;
        }
        printf("Case #%d: %I64d\n",t,ans);
    }
    return 0;
}

HDU 4975 这是个错题…  题意就是HDU 4888

思路:

这题标程的搜索就是错的  错误的方式可以用HDU 4888的数据来hack  说一下怎么解决错题 - -b  要么你和它一样错…  要么就是你网络流跑的快一点  为暴搜留出时间  这样兴许可以搜过去!!

代码:(我写的是和它一样错的…  只要是错的代码  跑的比标程都快…  建议本题别做!!)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAXN = 1010;
const int MAXM = 1010 * 1010 * 2;
const int INF = 2000000000;

struct Node {
    int from, to, next, cap;
} edge[MAXM];
int tol, n;
int head[MAXN], dep[MAXN], gap[MAXN], sumx[MAXN], sumy[MAXN], vis[MAXN];

void addedge(int u, int v, int w) {
    edge[tol].from = u;
    edge[tol].to = v;
    edge[tol].cap = w;
    edge[tol].next = head[u];
    head[u] = tol++;

    edge[tol].from = v;
    edge[tol].to = u;
    edge[tol].cap = 0;
    edge[tol].next = head[v];
    head[v] = tol++;
}
int que[MAXN];
void BFS(int start, int end) {
    memset(dep, -1, sizeof(dep));
    memset(gap, 0, sizeof(gap));
    gap[0] = 1;
    int front, rear, u, v, i;
    front = rear = 0;
    dep[end] = 0;
    que[rear++] = end;
    while (front != rear) {
        u = que[front++];
        for (i = head[u]; i != -1; i = edge[i].next) {
            v = edge[i].to;
            if (dep[v] != -1)
                continue;
            que[rear++] = v;
            dep[v] = dep[u] + 1;
            ++gap[dep[v]];
        }
    }
}
int cur[MAXN], S[MAXN];
int SAP(int start, int end) {
    int i, u, res = 0, top = 0, temp, inser;
    BFS(start, end);
    memcpy(cur, head, sizeof(head));
    u = start;
    while (dep[start] < n) {
        if (u == end) {
            temp = INF;
            for (i = 0; i < top; i++)
                if (temp > edge[S[i]].cap) {
                    temp = edge[S[i]].cap;
                    inser = i;
                }
            for (i = 0; i < top; i++) {
                edge[S[i]].cap -= temp;
                edge[S[i] ^ 1].cap += temp;
            }
            res += temp;
            top = inser;
            u = edge[S[top]].from;
        }
        if (u != end && gap[dep[u] - 1] == 0)
            break;
        for (i = cur[u]; i != -1; i = edge[i].next)
            if (edge[i].cap != 0 && dep[u] == dep[edge[i].to] + 1)
                break;
        if (i != -1) {
            cur[u] = i;
            S[top++] = i;
            u = edge[i].to;
        } else {
            int min = n;
            for (i = head[u]; i != -1; i = edge[i].next) {
                if (edge[i].cap == 0)
                    continue;
                if (min > dep[edge[i].to]) {
                    min = dep[edge[i].to];
                    cur[u] = i;
                }
            }
            --gap[dep[u]];
            dep[u] = min + 1;
            ++gap[dep[u]];
            if (u != start)
                u = edge[S[--top]].from;
        }
    }
    return res;
}

bool sol(int u, int fa) {
    int i, v;
    vis[u] = 1;
    for (i = head[u]; ~i; i = edge[i].next) {
        v = edge[i].to;
        if (!edge[i].cap || v == fa || vis[v] == 2)
            continue;
        if (vis[v] == 1 || sol(v, u))
            return true;
    }
    vis[u] = 2;
    return false;
}

bool findcircle(int fn) {
    for (int i = 1; i <= fn; i++) {
        vis[i] = 1;
        if (sol(i, i))
            return true;
        vis[i] = 2;
    }
    return false;
}

int main() {
    //freopen("1005.in", "r", stdin);
    //freopen("1005.txt", "w", stdout);
    int i, j, n1, n2, ans, End, CAS, fff = 1;
    scanf("%d", &CAS);
    while (CAS--) {
        scanf("%d%d", &n1, &n2);
        sumx[0] = sumy[0] = 0;
        for (i = 1; i <= n1; i++) {
            scanf("%d", &sumx[i]);
            sumx[0] += sumx[i];
        }
        for (i = 1; i <= n2; i++) {
            scanf("%d", &sumy[i]);
            sumy[0] += sumy[i];
        }
        if (sumx[0] != sumy[0]) {
            printf("Case #%d: So naive!\n", fff++);
            continue;
        }
        End = n1 + n2 + 1;
        tol = 0;
        n = End + 1;
        for (i = 0; i < n; i++) {
            head[i] = -1;
            vis[i] = 0;
        }
        for (i = 1; i <= n1; i++) {
            addedge(0, i, sumx[i]);
            for (j = 1; j <= n2; j++)
                addedge(i, n1 + j, 9);
        }
        for (i = 1; i <= n2; i++)
            addedge(n1 + i, End, sumy[i]);
        ans = SAP(0, End);
        if (ans != sumx[0])
            printf("Case #%d: So naive!\n", fff++);
        else {
            if (findcircle(n1))
                printf("Case #%d: So young!\n", fff++);
            else
                printf("Case #%d: So simple!\n", fff++);
        }
    }
    return 0;
}
时间: 2024-11-10 00:49:29

2014多校联合十(HDU 4972 HDU 4973 HDU 4974 HDU 4975)的相关文章

2014多校第十场1004 || HDU 4974 A simple water problem

题目链接 题意 : n支队伍,每场两个队伍表演,有可能两个队伍都得一分,也可能其中一个队伍一分,也可能都是0分,每个队伍将参加的场次得到的分数加起来,给你每个队伍最终得分,让你计算至少表演了几场. 思路 : ans = max(maxx,(sum+1)/2) :其实想想就可以,如果所有得分中最大值没有和的一半大,那就是队伍中一半一半对打,否则的话最大的那个就都包了. 1 #include <cstdio> 2 #include <cstring> 3 #include <st

2014多校联合六(HDU 4923 HDU 4925 HDU 4927 HDU 4930)

HDU 4923 Room and Moor 题意:给出A序列  求满足题目所写的B序列  使得方差最小 思路:可以想到最后的结果中  B序列的值一定是一段一段的  那么我们可以类似贪心去搞  对于一段序列我们可以求出什么样的b值使得方差最小  即序列中1的个数除以序列长度  又因为B是单调的  可以用一个单调栈去模拟  复杂度远远小于n^2  不要被吓怕- 代码: #include<cstdio> #include<cstring> #include<algorithm&g

2014多校联合三 (HDU 4888 HDU 4891 HDU 4893)

HDU 4891 The Great Pan 签到题  他怎么说你就怎么做就好了  注意做乘法时候会爆int 代码: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long LL; int n; char s[2000000]; int flag1, flag2, sp, ansflag;

2014多校联合五(HDU 4911 HDU 4915 HDU 4920)

HDU 4911 Inversion 题意:n个数字  通过k次相邻交换  使得逆序对数最少 思路:如果序列为 XXXABYYY  假设A和B位置互换  易知X和AB.Y和AB的逆序对数不变  换句话说一次交换最多使逆序对减少1  那么只需要求原逆序对数和k进行比较即可 代码: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100100 type

2014多校联合八(HDU 4945 HDU 4946 HDU 4948 HDU 4950 HDU 4951 HDU 4952)

HDU 4945 2048 题意:给你一堆数字  问有几个子集可以拼出2048 思路: 拼数字的规则相当于让数字乘二  所以不是2^i的数字不会拼出2048  那么这些数可选可不选  即为2^cnt种可能 之后只要计算出有几个子集不可能拼出2048即可  不过简单的直接dp是2048*100000的复杂度的  会TLE 所以要变成先枚举元素  再枚举该种元素个数  再枚举2048种状态  然后利用组合求(组合里需要逆元) 为什么这样快?  因为比如枚举2^5这个元素的时候  最多取2^6个  枚

2014多校联合四(HDU 4901 HDU 4902 HDU 4905)

HDU 4901 The Romantic Hero 题意: 一串数字a  找一个位置分开  前面为S'后面为T'  从这两个集合中分别选出子集S和T  使得S中元素的"异或"值等于T中元素的"且"值  问一共几种方案 思路: 由于a[i]只有1024  那么无论怎么运算都不可能大于2047  又因为S和T有一个明显的分界  所以我们可以想到利用dp分左右两边处理  令l[i][j]表示从左到i位置且一定选取a[i]的情况下异或值为j的方案数  r[i][j]类似

2014多校联合七(HDU 4937 HDU 4938 HDU 4939 HDU 4941)

好几天没写题解了- 都怪我太弱  补题补不动- HDU 4937 Lucky Number 题意:一个数字如果只有3456这四种数字组成  那么这个数字是幸运的  问  给出一个x  它在几种进制下是幸运的  如果无穷输出-1 思路: 分类讨论  如果x是3或4或5或6  那么一定有无穷个进制满足(从十进制开始-)  直接输出-1 除去上述情况  那么我们可以将一个数字写成这样 a0 + a1*base + a2*base^2 +... = x 那么如果base的最高次只有1次或2次时  就是简

hdu 4865 Peter&amp;#39;s Hobby(2014 多校联合第一场 E)

Peter's Hobby Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 545    Accepted Submission(s): 237 Problem Description Recently, Peter likes to measure the humidity of leaves. He recorded a leaf

hdu 4865 Peter&#39;s Hobby(2014 多校联合第一场 E)

题意:已知昨天天气与今天天气状况的概率关系(wePro),和今天天气状态和叶子湿度的概率关系(lePro)第一天为sunny 概率为 0.63,cloudy 概率 0.17,rainny 概率 0.2.给定n天的叶子湿度状态,求这n天最可能的天气情况 分析:概率dp设 dp[i][j] 表示第i天天气为j的最大概率,pre[i][j]表示第i天天气最可能为j的前一天天气,dp[i][j]=max(dp[i-1][k]+log(wePro[k][j])+log(lePro[j][lePos[i]]

hdu 4869 Turn the pokers (2014多校联合第一场 I)

Turn the pokers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1265    Accepted Submission(s): 465 Problem Description During summer vacation,Alice stay at home for a long time, with nothing t