现在的位置: 首页 > 综合 > 正文

130801hdu多校第四场结题报告

2018年02月21日 ⁄ 综合 ⁄ 共 5631字 ⁄ 字号 评论关闭

1011 Fliping game

传送门

一道简单的博弈,题目给了我们一个n*m的方阵,要求每次选择一个正面向上的硬币然后将从这个硬币到(n,m)之间的所有硬币翻面。谁最后找不到能翻的硬币谁就输。

因为无论怎么翻都要翻最后一个,所以当最后一个是正面的时候你就获得了必胜的能力,因为无论你怎么翻你都有最后那个硬币可以翻,因此一个简单判断就可以了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>

using namespace std;

int s[105][105];
int n,m;

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                scanf("%d",&s[i][j]);
            }
        }
        if(s[n-1][m-1] == 0)
            printf("Bob\n");
        else
            printf("Alice\n");
    }
    return 0;
}

1008 Hehe

传送门

一道简单的DP记录hehe的数量然后进行dp运算就行了。

因为互相之间差值是斐波那契数列开了一个数组存差指,表示效果不错^_^

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>

using namespace std;

#define maxn 2005
#define MOD 10007
#define INF 0xfffffff

char s[12000];
int f[6000];

void get()
{
    f[1]=1;
    f[2]=2;
    for(int i=3; i<=6000; i++)
        f[i]=(f[i-1]+f[i-2])%MOD;
}
int main()
{
    get();
    int t,counter = 1;
    scanf("%d",&t);
    getchar();
    while(t--)
    {
        scanf("%s",s);
        int l=strlen(s);
        int ans=1;
        int al=0;
        for(int i=0; i<=l-4; i++)
        {
            if(s[i] == 'h' && s[i+1] == 'e')
            {
                int j = i+2;
                int sum = 1;
                while(s[j] == 'h'&&s[j+1] == 'e')
                {
                    sum++;
                    j+=2;
                }
                if(sum >= 2)
                {
                    al++;
                    ans = (f[sum] * ans)%MOD;
                }
                i = j-1;
            }
        }
        printf("Case %d: %d\n",counter++,ans);
    }
    return 0;
}

1001 Palindrome subsequence

传送门

比赛时当时看完就感觉是区间DP,立马一通写,可是在去重的时候却出现了问题,老是想着加法的方式结果每次去重都是大幅的消耗时间,最后各种TLE,看了其他大牛的结题报告之后才发现原来可以直接减来去重,当时就囧了。。

还是思路不够广啊T_T

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>

char s[1005];
int l;
int dp[1005][1005];

int main()
{
    int t,counter = 0;
    scanf("%d",&t);
    getchar();
    while(t--)
    {
        counter++;
        gets(s);
        l = strlen(s);
        memset(dp,0,sizeof(dp));
        for(int i = 0; i < l; i ++)
        {
            dp[i][i] = 1;
        }
        for(int i = 2; i <= l; i ++)
        {
            for(int j = 0; j + i - 1 < l; j ++)
            {
                int a = j;
                int b = j + i - 1;
                if(s[a] == s[b])
                {
                    dp[a][b] ++;
                }
                else
                {
                    if(a + 1 <= b - 1)
                    {
                        dp[a][b] -= dp[a+1][b-1];
                    }
                }
                dp[a][b] += dp[a + 1][b] + dp[a][b-1];
                dp[a][b] %= 10007;
            }
        }
        printf("Case %d: %d\n",counter,(dp[0][l-1]+10007)%10007);
    }
    return 0;
}

1004Strongly connected

传送门

题目以强连通为名,自然做法也与强连通相关,可怜我还兴致勃勃的推规律,真想挖个坑把自己埋了T_T

不过嘛,规律的式子还是对的,就是对象偏了,即假定现在是n个点m条边,我们求出最小强连通分量为h(要求是出入度不全为0的强连通图)

我们可以求出最后的答案ans = n * (n - 1)  -  h * (n - h) - m

最初没想到出入度的问题,纠结了好久,后来写好后也是各种判断,时间效率很差,但是至少能过了感觉很开心^_^

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>

using namespace std;

#define maxn 1000005

struct node
{
    int u,v,next;
} edge[1000005];

int head[1000005];
int pos;
int n,m;
int num[maxn];
bool in[maxn];
bool out[maxn];

inline void RD(int &ret)
{
    char c;
    do
    {
        c = getchar();
    }
    while(c < '0' || c > '9') ;
    ret = c - '0';
    while((c=getchar()) >= '0' && c <= '9')
        ret = ret * 10 + ( c - '0' );
}

void insert() //创建有向图
{
    int x,y;
    for(int i=0; i<m; i++)
    {
        RD(x);
        RD(y);
        edge[pos].u = x;
        edge[pos].v = y;
        edge[pos].next = head[x];
        head[x] = pos;
        pos++;
    }
}

int dfsn[maxn];
bool used[maxn];
int low[maxn];
int stack[maxn];
int scc[maxn];
int front;
int number;
int pre;
bool Instack[maxn];

void dfs(int now) //DFS缩点形成多个小的强连通图
{
    front++;
    stack[front] = now;
    used[now] = 1;
    dfsn[now] = low[now] = pre;
    pre++;
    Instack[now] = 1;
    for(int i = head[now]; i; i = edge[i].next) //搜到为0,即已经不存在前置节点结束
    {
        int v = edge[i].v;
        if(used[v] == 1) //所搜点已被使用的话则表示该点对应强连通图已被访问
        {
            if(Instack[v] == 1) //表示是此强连通图的记录点
                low[now] = min(low[now],dfsn[v]);
            continue;
        }
        dfs(v); //未找到对应位置需要继续DFS查找
        low[now] = min(low[now],low[v]);
    }
    if(low[now] == dfsn[now])//找到的强连通存在重叠需要特判,确定强连通的大小
    {
        number++;
        int mark;
        do
        {
            mark=stack[front--];
            scc[mark]=number;
            Instack[mark]=false;
        }
        while(mark!=now);
    }
}

void init()//输入内容初始化
{
    memset(dfsn,0,sizeof(dfsn));
    memset(low,0,sizeof(low));
    memset(used,0,sizeof(used));
    memset(Instack,0,sizeof(Instack));
    pre=1;
    number=0;
    memset(head,0,sizeof(head));
    pos=1;
}

void init2()//确定能分出两个全连通图后对出度入度初始化
{
    memset(num,0,sizeof(num));
    for(int i=1; i<=n; i++)
        num[scc[i]]++;
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
}

int main()
{
    int t,counter = 1;
    RD(t);
    while(t--)
    {
        RD(n);
        RD(m);
        init();
        insert();
        for(int i=1; i<=n; i++)
        {
            if(used[i] == 0)
            {
                front = -1;
                dfs(i);
            }
        }
        if(number == 1)//判断是否整体成强连通
        {
            printf("Case %d: -1\n",counter++);
            continue;
        }//没有整体强连通则存在解,开始求最小强连通大小
        init2();
        for(int i=1; i<pos; i++) //pos为目前已有的强连通的数量,对所有的强连通图进行计算
        {
            int x=edge[i].u;
            int y=edge[i].v;
            x=scc[x];
            y=scc[y];
            if(x != y)//不相等时存在出入度,变为1
            {
                in[y]=1;
                out[x]=1;
            }
        }
        int h = maxn;
        for(int i=1; i<=number; i++)
            if(in[i] == 0||out[i] == 0)//判断出入度确定是否可用
                h=min(h,num[i]);
        int ans = n * (n - 1) - h * (n - h) - m;//根据找出的最小强连通计算答案
        printf("Case %d: %d\n",counter++,ans);
    }
    return 0;
}

1007Group

传送门

题目要我们求在特定区域内存在的互相之间数字相邻的朋友的组数。

因为是10^5的数据,10^5的询问,在线写法几乎必爆,所以要改成用线段树或者树状数组进行离线处理,修改后就是简单的改改中间判断

很容易就能写出来了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>

using namespace std;

#define maxn 100005

int n,m;
int s[maxn];
int a[maxn];
int ss1[maxn];
int ans[maxn];

int lowbit(int x)
{
    return x&(-x);
}

void add(int i,int val)
{
    while(i <= n)
    {
        s[i] += val;
        i += lowbit(i);
    }
}

int sum(int i)
{
    int sum = 0;
    while(i > 0)
    {
        sum += s[i];
        i -= lowbit(i);
    }
    return sum;
}

struct node
{
    int l,r;
    int index;
}tt[maxn];

bool cmp(node x,node y)
{
    return x.l < y.l;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        memset(s,0,sizeof(s));
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&a[i]);
            ss1[a[i]]=i;
        }
        ss1[0] = maxn;
        ss1[n+1] = maxn;
        for(int i = 1;i <= n;i++)
        {
            if(i < ss1[a[i]-1] && i < ss1[a[i]+1])
                add(i,1);
            else if(i > ss1[a[i]-1] && i > ss1[a[i]+1])
                add(i,-1);
        }
        for(int i = 0;i < m;i++)
        {
            scanf("%d%d",&tt[i].l,&tt[i].r);
            tt[i].index = i;
        }
        sort(tt,tt+m,cmp);
        int i = 1;
        int j = 0;
        while(j < m)
        {
            while(i <= n && i < tt[j].l)
            {
                if(i > ss1[a[i]-1] && i > ss1[a[i]+1])
                    add(i,-1);
                else if(i < ss1[a[i]-1] && i < ss1[a[i]+1])
                {
                    int Min = min(ss1[a[i]-1],ss1[a[i]+1]);
                    int Max = max(ss1[a[i]-1],ss1[a[i]+1]);
                    add(i,-1);
                    add(Min,1);
                    add(Max,1);
                }
                else if(i < ss1[a[i]-1])
                {
                    add(i,-1);
                    add(ss1[a[i]-1],1);
                }
                else
                {
                    add(i,-1);
                    add(ss1[a[i]+1],1);
                }
                i++;
            }
            while( j < m && tt[j].l <= i)
            {
                ans[tt[j].index]= sum(tt[j].r);
                j++;
            }
        }
        for(int i = 0;i < m;i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}

1003Swipe Bo

传送门

冰面行走找出口的大模拟,情况略多,需要慢慢处理,整理好了再发上来^_^

抱歉!评论已关闭.