2012 Multi-University Training Contest 1[hdu4300~4309]

4300 一开始向到了后缀数组, 后来才弱爆了发现是kmp的变形, 修改下匹配的起点, 并且返回的是文本串匹配完时模式串当前的位置就可以了, 比赛的时候真是弱爆了T.T

 

#include <cstring>
#include <cstdio>

using namespace std;
const int maxn=100000+5;
char pat[maxn], str[maxn];
int P[maxn];

/// need *P, *pat and *str
int kmp()
{
    int i, j;
    int len=strlen(str);
    for (P[0]=-1,i=1; pat[i]; ++i)
    {
        for (j=P[i-1]; j>=0 && pat[i]!=pat[j+1]; j=P[j]);
        if(pat[j+1]==pat[i])P[i]=j+1;
    }
    for (i=(len+1)/2, j=-1; str[i]; ++i)
    {
        while (j>=0 && pat[j+1]!=str[i])j=P[j];
        if(pat[j+1]==str[i])++j;
//        if(pat[j+1]==0)
//            return i-j;/// return the first pos
    }
    return i-j-1;
}

char s[40];
char ss[40];
int main()
{
    int cas; scanf("%d", &cas);
    while (cas--)
    {
        scanf("%s%s", s, str);
        for (int j=0; j<26; ++j)
            ss[s[j]-'a']=j+'a';
        for (int i=0; str[i]; ++i)
        {
            pat[i]=ss[str[i]-'a'];
        }
        int len=strlen(str); pat[len]='\0';
        //printf("%s %s\n", pat, str);
        int ans=kmp();
        for (int i=0; i<ans; ++i)
            printf("%c", str[i]);
        for (int i=0; i<ans; ++i)
            printf("%c", pat[i]);
        puts("");
    }
    return 0;
}


 

 

4303 赤裸裸的树形dp, 连推带敲带调,花2、3个小时, 很威武的题

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cmath>

#include <vector>
#include <stack>
#include <map>
#include <queue>

const double pi=cos(-1.);
const double eps=10e-6;
const double eps1=10e-10;
const int inf=0x7fffffff;
const int inff=2021161080; /// memset 120!
const long long infl=1ll<<62;

///******macro defination******///
#define cas(a) int a; scanf("%d", &a); while (a--)
#define cas1(x, a) int a; scanf("%d", &a); for (int x=1; x<=a; ++x)
#define int(a) int a; scanf("%d", &a)
#define char(a) char a; scanf("%c", &a)
#define strr(a, x) char a[x]; scanf("%s", &a)
#define clean(a) memset (a, 0, sizeof(a));
#define up(x,a) for(int x=0; x<a; ++x)
#define down(x,a) for(int x=a-1; x>=0; --x)
#define up1(x,a) for (int x=1; x<=a; ++x)

#define debug(a) printf("here is %d!!!\n", a);
///*** mathmatics ***///
#define sqr(x) (x)*(x)
#define abs(x) (x)>0?(x):(-(x))
#define zero(x) (x)<eps && (x)>eps
///******   by Geners   ******///
typedef long long ll;
typedef unsigned int UI;

using namespace std;

const int maxn=300000+123;
int node[maxn];
struct Edge{
    int v, color, next;
}edge[maxn<<1];

int cnt, head[maxn];
void addedge(int u, int v, int w)
{
    edge[cnt].color=w;
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;

    edge[cnt].color=w;
    edge[cnt].v=u;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}

void init()
{
    cnt=0;
    memset (head, -1, sizeof(head));
}

ll num[maxn], sum[maxn];
ll ans;
/** 子节点返回给父节点的值是与父节点能构成的路径数num
  *   以及能与父节点构成路径的所有路径的结点和sum。
  *   sum 根据pcolor来求
  *  子节点之间怎么办? 思考中。。。map!
**/


void dfs(int u, int fa, int pw)
{
    num[u]=1;
    sum[u]=node[u];
    map<int, pair<ll, ll> >son;
    map<int, pair<ll, ll> >::iterator it;
    ll cou=0, pro=0;
    for (int p=head[u]; ~p; p=edge[p].next)
    {
        const int &v=edge[p].v, &w=edge[p].color;

        if(v==fa)continue;

        dfs(v, u, w);
        //printf("v=%d u=%d ans==%lld\n", v+1, u+1, ans);
        if(w!=pw)
        {
            num[u]+=num[v];
            sum[u]+=sum[v]+node[u]*num[v];
        }
        cou+=num[v];
        if(son.find(w)==son.end())
        {
            pair<int, int> ii;
            ii.first = num[v];
            ii.second = sum[v];
            son[w]=ii;
        }
        else
        {
            son[w].first+=num[v];
            son[w].second+=sum[v];
        }
        //ans+=sum[u];
        ans+=sum[v]+node[u]*num[v];
    }
    //printf("%d cou==%lld totol==%lld\n", u+1, cou, totol);
    for (it=son.begin(); it!=son.end(); it++)
    {
        ll c=it->second.first, s=it->second.second;
        pro+=node[u]*(cou-c)*c;
        ans+=s*(cou-c);
        //printf("c==%lld s==%lld pro==%lld ans==%lld  tmp==%lld\n", c, s, pro, ans, s*(cou-c));
    }
    ans+=pro/2;
    //ans+=sum[u];
    //printf("u==%d, ans==%lld\n", u+1, ans);
}

int main ()
{
    int n;
    while (~scanf("%d", &n))
    {
        init();
        for (int i=0; i<n; ++i) scanf("%d", node+i);
        for (int i=1; i<n; ++i)
        {
            int a, b, c; scanf("%d%d%d", &a, &b, &c);
            addedge(a-1, b-1, c);
        }
        ans=0;

        dfs(0, -1, -1);

        printf("%I64d\n", ans);
    }
    return 0;
}
/*
6
6 2 3 7 1 4
1 2 1
1 3 2
1 4 3
2 5 1
2 6 2

3
1 2 3
1 2 1
2 3 2
3
1 2 0
1 2 1
2 3 1

4
1 2 3 4
1 2 1
2 3 2
3 4 1

7
6 2 3 7 1 4 1
1 2 1
1 3 2
1 4 3
2 5 1
2 6 2
5 7 2
*/


 

4309 网络流,

三种边, 桥, 路, 隧道, 连接各个城市, 很容易想到对隧道的处理, 关键是桥的费用的问题, 一直没想到怎么处理, 看到题解说是桥的个数小于等于12,直接暴力枚举,跑2^12次最大流,瞬间巨无语,敲完交, 直接跪, 调半天看题解, 发现对桥的处理还有一个当不修桥还可以通过一人,回去一个题意还真是,直接给题意跪了。

 

 http://acm.hdu.edu.cn/showproblem.php?pid=4309

又新敲了遍sap

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int inf=0x7fffffff;

const int N=200;
const int M=10000;

struct Edge{
    int v, next, w;
}edge[M<<2];
int cnt, head[N];
void addedge(int u, int v, int w)
{
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;

    edge[cnt].v=u;
    edge[cnt].w=0;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}
int sap(int s, int t)
{
    int pre[N], cur[N], dis[N], gap[N];
    int flow=0, aug=inf, u;
    bool flag;
    for (int i=0; i<=t; ++i)
    {
        cur[i]=head[i], gap[i]=dis[i]=0;
    }
    u=pre[s]=s; gap[s]=t+1;/// 倒序分层
    while(dis[s]<=t)
    {
        flag=false;
        for (int &p=cur[u]; ~p; p=edge[p].next)
        {/// 从当前弧开始寻找
            const int &v=edge[p].v, &w=edge[p].w;
            if(w>0 && dis[u]==dis[v]+1)
            {
                flag=true;
                if(w<aug)aug=w;///寻找增广路上的最小值
                pre[v]=u; u=v;
                if(u==t)/// 如果增广到汇点
                {
                    for (flow+=aug; u!=s;)
                    {
                        u=pre[u];
                        edge[cur[u]].w-=aug;
                        edge[cur[u]^1].w+=aug;
                    }
                    aug=inf;
                }
                break;
            }
        }
        if(flag)continue;/// 直到未找到增广路
        int mindis=t+1;
        for (int p=head[u]; ~p; p=edge[p].next)
        {///当前弧优化的理解还是不太到位
            const int &v=edge[p].v, &w=edge[p].w;
            if(w>0 && dis[v]<mindis)
                mindis=dis[v], cur[u]=p;
        }
        if(--gap[dis[u]]==0)break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return flow;
}

void init()
{
    cnt=0;
    memset(head, -1, sizeof(head));
}

int a[M], b[M], c[M], total;

void build()
{
    init();
    for (int i=0; i<total; ++i)
    {
        addedge(a[i], b[i], c[i]);
    }
}


int bu[20], bv[20], bc[20];
int main()
{
    int n, m;
    while (~scanf("%d%d", &n, &m))
    {
        total=0;
        int t=n, bridge=0;
        for (int i=1; i<=n; ++i)
        {
            int v; scanf("%d", &v);
            a[total]=0; b[total]=i; c[total++]=v;
        }
        for (int i=0; i<m; ++i)
        {
            int u, v, w, p; scanf("%d%d%d%d", &u, &v, &w, &p);
            if(p==0)
            {
                a[total]=u, b[total]=v, c[total++]=inf;
                //a[total]=v, b[total]=u, c[total++]=inf;
            }else
            if(p<0)
            {
                t++;
                a[total]=u, b[total]=t, c[total++]=inf;
                a[total]=t, b[total]=v, c[total++]=inf;
                a[total]=t, b[total]=151, c[total++]=w;
            }else
            {
                bu[bridge]=u, bv[bridge]=v, bc[bridge++]=w;
            }
        }
        int ans=-1, cost=inf;
        for (int i=0; i<(1<<bridge); ++i)
        {
            build();
            int tmpc=0;
            for (int j=0; j<bridge; ++j)
            {
                if(i&(1<<j))
                {
                    tmpc+=bc[j];
                    addedge(bu[j], bv[j], inf);
                    //addedge(bv[j], bu[j], inf);
                }
                else addedge(bu[j], bv[j], 1);
            }
            int tmpa=sap(0, 151);
            if(tmpa==ans) cost=min(cost, tmpc);
            if(tmpa>ans)
            {
                ans=tmpa;
                cost=tmpc;
            }
            //printf("%d %d %d\n", i, ans, cost);
        }
        if(ans>0)
            printf("%d %d\n", ans, cost);
        else
            puts("Poor Heaven Empire");
    }
    return 0;
}


 

 

 


 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值