10月集训test13

终于不是地主家的傻儿子企鹅豆豆了。。。
今天是运动会的第一天,锣鼓喧天,热闹非凡。。。而我在考试。。
呵呵。
然而还是感谢WKL凯爷对题的讲解以及详尽的分析。
上题。

1.抄代码

给出几个字符串,两个一组,若其中一个字符串能够由另一个经过多次变换得到,则输出1,否则输出0。
变换的意思是指将字符串中的所有小写字母x变为y(此处x,y代指任意小写字母)
字符串仅由小写字母,数字,空格和分号组成。

输入格式

第一行一个整数T。
接下来2T行,每2i行代表一组字符串。

输出格式

输出T行,若能变换输出1,否则输出0。

输入样例

5
int x;
int y;
double a;
double aa;
float 1
float 2
string s;
double d;
print thisismycode;
float tooooooooooo;

输出样例

1
0
0
1
1

关于这道题,真的不知道应该说什么。。。。。。
其实可能并不难。。吧。。毕竟连出题的人都没有考虑全所有情况,题解都是错的,但是对于这道题的数据来说足够了。
嗯,长度不一样不能换,非小写字母为不一样不能换,同一小写字母对的不一样不能换。
但是还是少了可能性:

abcdefghijklmnopqrstuvwxyz
zyxwvutsrqponmlkjihgfedcba

这样应该是换不了的。(不过鉴于数据干脆就不考虑了吧。)

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;

int t,len1,len2;
bool f;
char a[1010],b[1010],aa[50];

inline int read()
{
    int i=0;char c;
    for(c=getchar();c<'0'||c>'9';c=getchar());
    for(;c>='0'&&c<='9';c=getchar())
        i=(i<<1)+(i<<3)+c-'0';
    return i;
}

int main()
{
    //freopen("copycat.in","r",stdin);
    //freopen("copycat.out","w",stdout);

    t=read();
    while(t--)
    {
        memset(aa,0,sizeof(aa));
        f=1;
        gets(a);gets(b);
        len1=strlen(a);
        len2=strlen(b);
        if(len1!=len2)
        {
            cout<<0<<endl;
            continue;
        }
        for(int i=0;i<len1;i++)
            if(a[i]!=b[i])
            {
                if(a[i]<'a'||a[i]>'z'||b[i]<'a'||b[i]>'z')
                    {f=0;break;}
                if(!aa[a[i]-'a'])
                    aa[a[i]-'a']=b[i];
                else if(aa[a[i]-'a']!=b[i])
                        {f=0;break;}
            }
        cout<<f<<endl;
    }
    return 0;
}

2.做运动

Y要从教学楼跑到食堂。
学校为一个无向图,每条路的温度为t,通过的时间为c,Y在温度为t的路上走单位时间,热量增加t。
给出教学楼和食堂的位置,在经过的所有道路中最高温度最低的前提下,使Y到达食堂时的热量最低。(原热量为0)

输入格式

第一行两个正整数n,m,代表学校中的地点数和道路数。
接下来m行,每行四个整数a,b,t,c分别代表双向道路的两个端点,温度和通过所需时间。
最后一行两个整数S和T,代表教学楼和食堂编号。

输出格式

输出一行两个整数,分别代表最高温度和最终热量。

输入样例

5 6
1 2 1 2
2 3 2 2
3 4 3 4
4 5 3 5
1 3 4 1
3 5 3 6
1 5

输出样例

3 24

这道题共有两种做法。
由于以最高温度最低为前提,则重点在温度上。
二分温度,跑一遍dfs判断图是否连通,若连通最高温度再降低,否则升高。最后跑一遍最短路Dijkstra
或者将所有边按温度大小排序加入,用并查集维护S到T的连通性,在第一个连通的温度下跑一遍Dijkstra
注意第二种方法加边时,同一温度的多条边要同时加入。

//二分温度,用dfs判是否连通,若连通跑一遍 dijkstra
//按温度从小到大加边,注意同一温度的要同时加,用并查集判是否连通,跑一遍dijkstra 
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
using namespace std;

struct node
{
    int next,to,t,u;
    long long c;
}a[2000010],f[1000010];
int n,m,s,tot,d,tt,fa[500010],first[500010];
long long dis[500010];
bool flag[500010];

inline int read()
{
    int i=0;char c;
    for(c=getchar();c<'0'||c>'9';c=getchar());
    for(;c>='0'&&c<='9';c=getchar())
        i=(i<<1)+(i<<3)+c-'0';
    return i;
}

inline void add(int x,int y,long long w,long long aa)
{
    a[++tot].next=first[x];
    first[x]=tot;
    a[tot].to=y;
    a[tot].t=w;
    a[tot].u=x;
    a[tot].c=aa*w;
}

inline int gf(int x)
{
    if(fa[x]!=x)
        fa[x]=gf(fa[x]);
    return fa[x];
}

inline void dfs()
{
    for(int i=1;i<=m;i++)
    {
        int fx=gf(f[i].u),fy=gf(f[i].to);
        if(fx!=fy)
        {
            fa[fy]=fx;
            d=f[i].t;
        }
        if(gf(s)==gf(tt))
            break;
    }
}

inline void zql(int s)
{
    priority_queue<pair<long long,int> >q;
    memset(dis,127,sizeof(dis));
    dis[s]=0;
    q.push(make_pair(0,s));
    while(!q.empty())
    {
        pair<long long,int>now=q.top();
        q.pop();
        if(now.second==tt) break;
        if(flag[now.second]) continue;
        flag[now.second]=1;
        for(int p=first[now.second];p;p=a[p].next)
            if(!flag[a[p].to]&&dis[a[p].to]>dis[now.second]+a[p].c)
            {
                dis[a[p].to]=dis[now.second]+a[p].c;
                q.push(make_pair(-dis[a[p].to],a[p].to));
            }
    }
}

inline bool comp(node a,node b)
{
    return a.t<b.t;
}

int main()
{
    freopen("running.in","r",stdin);
    freopen("running.out","w",stdout);

    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        f[i].u=read();
        fa[f[i].u]=f[i].u;
        f[i].to=read();
        fa[f[i].to]=f[i].to;
        f[i].t=read();
        f[i].next=read();
    }
    sort(f+1,f+m+1,comp);
    s=read(),tt=read();
    dfs();
    for(int i=1;i<=m;i++)
        if(f[i].t<=d)
        {
            add(f[i].u,f[i].to,f[i].t,f[i].next);
            add(f[i].to,f[i].u,f[i].t,f[i].next);
        }
        else break; 
    zql(s);
    printf("%d %lld\n",d,dis[tt]);
    return 0;
}

3.大逃杀

地图上有n个点,由n-1条无向边连接,保证连通,通过每一条边需要花费一定的时间。
有些点上有资源,获取资源可以增强武力值wi,可以选择不获取;有些点上有敌人,需要花费ti的时间杀死敌人,不能无视敌人,武力值和杀死敌人的时间没有关系。
若某个点上既有资源又有敌人,必须先杀了敌人再拿资源。获取资源不需要时间。
总时间为T,希望时间结束前武力值尽量大。

输入格式

第一行n和T,代表点数和时间。
第二行n个整数为wi。
第三行n个整数为ti。
接下来n-1行,每行三个整数a,b,c代表通过连接a和b的双向道路所花时间为C。

输出格式

一个整数代表最大武力值。

输入样例

17 54
5 5 1 1 1 25 1 10 15 3 6 6 66 4 4 4 4
0 1 3 0 0 0 1 3 2 0 6 7 54 0 0 0 0
1 8 3
2 8 3
8 7 7
7 13 0
7 14 0
15 14 2
16 14 3
17 14 5
7 9 4
9 10 25
10 11 0
10 12 0
7 6 20
3 6 3
3 4 3
3 5 3

输出样例

68

这道题。。怎么说呢。。。好吧我真的没有往树型DP的方向去想。
不过WKL凯爷的分析很有道理,求子树的时候,大部分都用了树型DP。
开一个三维数组f[i][j][3],状态转移的时候只需要dfs一遍。
f[i][j][0]代表进入以i为根的子树并回到i;
f[i][j][1]代表进入以i为根的子树并不回到i;
f[i][j][2]代表从以i为根的子树内出发,经过i并回到以i为根的子树内;
用j秒能得到的最大武力值。
更新的时候用i的一个儿子从大到小枚举j更新i的答案。
答案是所有子树的最大值。

唔。。。用一下别人的代码。。这个状态转移异常的容易写错。。。
@g19zjj

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#define ll long long
using namespace std;

int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
    if(c=='-')f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}

const int N=305;
int n,T,val[N],t[N],f[N][N][3],tmp[N];
int tot,first[N],nxt[N<<1],to[N<<1],w[N<<1];

void add(int x,int y,int z)
{
    nxt[++tot]=first[x],first[x]=tot,to[tot]=y,w[tot]=z;
}

void dfs(int u,int fa)
{
    int i,j;
    for(int i=t[u];i<=T;i++)
        f[u][i][0]=f[u][i][1]=f[u][i][2]=val[u];
    for(int e=first[u];e;e=nxt[e])
    {
        int v=to[e];
        if(v==fa)continue;
        dfs(v,u);

        for(i=0;i<=T;i++)tmp[i]=f[u][i][2];
        for(j=0;j<=T;j++)
        {
            for(i=2*w[e]+j+t[u];i<=T;i++)
                tmp[i]=max(tmp[i],f[u][i-2*w[e]-j][2]+f[v][j][0]);
            for(i=2*w[e]+j+t[u];i<=T;i++)
                tmp[i]=max(tmp[i],f[u][i-2*w[e]-j][0]+f[v][j][2]);
            for(i=w[e]+j+t[u];i<=T;i++)
                tmp[i]=max(tmp[i],f[u][i-w[e]-j][1]+f[v][j][1]);
        }
        for(i=0;i<=T;i++)f[u][i][2]=tmp[i];

        for(i=0;i<=T;i++)tmp[i]=f[u][i][1];
        for(j=0;j<=T;j++)
        {
            for(i=2*w[e]+j+t[u];i<=T;i++)
                tmp[i]=max(tmp[i],f[u][i-2*w[e]-j][1]+f[v][j][0]);
            for(i=w[e]+j+t[u];i<=T;i++)
                tmp[i]=max(tmp[i],f[u][i-w[e]-j][0]+f[v][j][1]);
        }
        for(i=0;i<=T;i++)f[u][i][1]=tmp[i];

        for(i=0;i<=T;i++)tmp[i]=f[u][i][0];
        for(j=0;j<=T;j++)
            for(i=2*w[e]+j+t[u];i<=T;i++)
                tmp[i]=max(tmp[i],f[u][i-2*w[e]-j][0]+f[v][j][0]);
        for(i=0;i<=T;i++)f[u][i][0]=tmp[i];
    }
}

int main()
{
    //freopen("lx.in","r",stdin);
    //freopen("toyuq.out","w",stdout);
    int x,y,z;
    n=getint(),T=getint();
    for(int i=1;i<=n;i++)val[i]=getint();
    for(int i=1;i<=n;i++)t[i]=getint();
    for(int i=1;i<n;i++)
    {
        x=getint(),y=getint(),z=getint();
        add(x,y,z),add(y,x,z);
    }
    dfs(1,0);
    int ans=0;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=T;j++)
            for(int k=0;k<3;k++)
                ans=max(ans,f[i][j][k]);
    cout<<ans;
}

没有然后了。
来自2017.10.26.

——我认为return 0,是一个时代的终结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值