集训队日常训练20180513-DIV1

A.3132

给一个有向图,问能否从任意点出发都能进入一个环中。

深搜。

#include<bits/stdc++.h>
using namespace std;

const int N=55;
vector<int>G[N];
bool vis[N];
int f;
void dfs(int u)
{
    if(f)return;
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(!vis[v])
        {
            vis[v]=1;
            dfs(v);
        }
        else
        {
            f=1;
            return;
        }
    }
}
int main()
{
    int n,m;
    char s1[5],s2[5];
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)G[i].clear();
        for(int i=0;i<m;i++)
        {
            int u,v;
            scanf("%s%s",s1,s2);
            G[s1[0]-'A'+1].push_back(s2[0]-'A'+1);
        }
        for(int i=1;i<=n;i++)
        {
            f=0;
            memset(vis,0,sizeof vis);
            dfs(i);
            if(!f)break;
        }
        printf("%s\n",f?"YES":"NO");
    }
    return 0;
}
A.cpp

B.4971

给一颗树,n个起点,问到1的路径权值和,一个点的权值只算一次。

深搜。

#include<bits/stdc++.h>
using namespace std;

const int N=1005;
vector<int>G[N];
bool vis[N];
int father[N],be[N],val[N];
void dfs(int u,int fa)
{
    father[u]=fa;
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(v==fa)continue;
        dfs(v,u);
    }
}
int main()
{
    int n,m,ca=1;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(vis,0,sizeof vis);
        for(int i=1;i<=n;i++)G[i].clear();
        for(int i=1;i<=m;i++)
            scanf("%d",&be[i]);
        for(int i=1;i<=n;i++)
            scanf("%d",&val[i]);
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1,0);
        int sum=0;
        for(int i=1;i<=m;i++)
        {
            int f=be[i];
            if(!vis[f])vis[f]=1,sum+=val[f];
            while(f)
            {
                f=father[f];
                if(!vis[f])vis[f]=1,sum+=val[f];
            }
        }
        printf("Case #%d: %d\n",ca++,sum);
    }
    return 0;
}
B.cpp

C.4976

给一个二进制串,其中有一堆未知数,问有几种填法使得十进制数中含6。

深搜。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
int p[1005];

string s;
int l;
int num=0;
void dfs(int pos,ll ans)
{
    if(pos==l)
    {
        while(ans)
        {
            if(ans%10==6)
            {
                num++;
                break;
            }
            ans=ans/10;
        }
        return;
    }
    if(s[pos]=='0') dfs(pos+1,ans*2);
    else if(s[pos]=='1') dfs(pos+1,ans*2+1);
    else
    {
        dfs(pos+1,ans*2);
        dfs(pos+1,ans*2+1);
    }
}
int main()
{
    while(cin>>s)
    {
       num=0;
       l=s.size();
       dfs(0,0);
       cout<<num<<endl;
    }
    return 0;
}
C.cpp

D.4546

M段区间每段区间只能有一张假票,问最多能有几张假票,若不合法输出-1。

不会(待补)

E.4587

有两颗苹果树,贝西初始站在1下,每分钟掉下1个苹果,贝西最多移动W次,问T分钟贝西最多能接到多少苹果。

dp[t][w][3]表示在t分钟移动w次现在站在苹果树几下。

#include<bits/stdc++.h>
using namespace std;
int dp[1005][35][2];
int main()
{
    for(int i=0;i<1005;i++)
        for(int j=0;j<35;j++)
            dp[i][j][0]=dp[i][j][1]=-1000000000;
    int T,W;
    scanf("%d%d",&T,&W);
    for(int i=0;i<T;i++) dp[i][W][0]=0;
    for(int i=0,x;i<T;i++)
    {
        scanf("%d",&x);
        if(!i)
        {
            if(x==1) dp[i][W][0]=1;
            else if(x==2) dp[i][W-1][1]=1;
        }
        else
        {
            for(int j=W;j>=0;j--)
            {
                if(x==1)
                {
                    dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][0]+1);
                    if(j!=W) dp[i][j][0]=max(dp[i][j][0],dp[i-1][j+1][1]+1);
                    dp[i][j][1]=max(dp[i][j][1],dp[i-1][j][1]);
                    if(j!=W) dp[i][j][1]=max(dp[i][j][1],dp[i-1][j+1][0]);
                }
                else if(x==2)
                {
                    dp[i][j][1]=max(dp[i][j][1],dp[i-1][j][1]+1);
                    if(j!=W) dp[i][j][1]=max(dp[i][j][1],dp[i-1][j+1][0]+1);
                    dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][0]);
                    if(j!=W) dp[i][j][0]=max(dp[i][j][0],dp[i-1][j+1][1]);
                }
            }
        }
    }
    int ans=0;
    for(int i=0;i<=W;i++)
        ans=max(ans,max(dp[T-1][i][0],dp[T-1][i][1]));
    printf("%d\n",ans);
    return 0;
}
E.cpp

F.4596

n个盒子按1-n编号,m次操作,1XY把x放在y左边,2XY把x放在y右边,3XYxy互换位置,4翻转,问操作完所有奇数位置的盒子编号之和。

双向链表,L[i]=i-1,R[i]=i+1,着实有点难写。

#include<stdio.h>
#include<string.h>
#define maxn 100000+5
typedef long long LL;
int pre[maxn],next[maxn],n,m;
int main()
{
    int T=0;
    while(~scanf("%d%d",&n,&m))
    {
        int tot=0;
        for(int i=1;i<=n;++i)
        {
            pre[i]=i-1;
            next[i]=i+1;
        }
        next[n]=0;
        //
        int op,x,y;
        for(int i=1;i<=m;++i)
        {
            scanf("%d",&op);
            if(op!=4)
            scanf("%d%d",&x,&y);
            else
            {
                ++tot;
                continue;
            }
            if((tot&1)&&op<3)
                op=3-op;
            if(op==1)
            {
            if(pre[y]==x)
            continue;
            next[pre[x]]=next[x];
            pre[next[x]]=pre[x];
            next[pre[y]]=x;
            pre[x]=pre[y];
            next[x]=y;
            pre[y]=x;
            }
            else if(op==2)
            {
                if(next[y]==x)
                    continue;
                next[pre[x]]=next[x];
                pre[next[x]]=pre[x];
                pre[next[y]]=x;
                next[x]=next[y];
                pre[x]=y;
                next[y]=x;
            }
            else if(op==3)
            {
                if(next[x]==y)
                {
                    int temp1=pre[x],temp2=next[y];
                    next[temp1]=y;
                    pre[y]=temp1;
                    pre[temp2]=x;
                    next[x]=temp2;
                    next[y]=x;
                    pre[x]=y;
                }
                else if(next[y]==x)
                {
                    int temp1=pre[y],temp2=next[x];
                    next[temp1]=x;
                    pre[x]=temp1;
                    pre[temp2]=y;
                    next[y]=temp2;
                    next[x]=y;
                    pre[y]=x;
                }
                else
                {
                    int temp1=next[y],temp2=pre[y];
                    next[pre[x]]=y;
                    pre[next[x]]=y;
                    next[pre[y]]=x;
                    pre[next[y]]=x;
                    next[y]=next[x];
                    pre[y]=pre[x];
                    next[x]=temp1;
                    pre[x]=temp2;
                }
            }
        }
           int *st,*ed;
            if(tot&1)
            {
                st=next;
                ed=pre;
            }
            else
            {
                st=pre;
                ed=next;
            }
            LL ans=0;
            for(int i=1;i<=n;++i)
            {
                if(!st[i])//寻找开头
                {
                    for(int j=1; i ;i=ed[i],++j)//判断结尾,i=0也就是末尾的时候循环结束
                        if(j&1)
                        ans+=i;
                    break;
                }
            }
        printf("Case %d: %lld\n",++T,ans);
    }
    return 0;
}
F.cpp

G.5066

n个点m条有向边,问从1出发最多经过几个点再回到1。

targin求含有1的强连通集合。

#include<bits/stdc++.h>
using namespace std;

const int N=1e5+5;
int low[N],dfn[N],Stack[N],tot,cnt;
bool instack[N];
vector<int>G[N];
void tarjan(int u)
{
    int v;
    dfn[u]=low[u]=++tot;
    Stack[++cnt]=u;
    instack[u]=true;
    for(int i=0;i<G[u].size();i++)
    {
        v=G[u][i];
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(instack[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        int sz=0;
        while(v=Stack[cnt--])
        {
            instack[v]=false;
            sz++;
            if(u==v)break;
        }
        if(u==1)printf("%d\n",sz);
    }
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
    }
    tarjan(1);
    return 0;
}
G.cpp

H.5129

题意不明

不会(待补)

I.5166

n个点构造一个哈夫曼树。

贪心每次取两个最小的。

#include<bits/stdc++.h>
using namespace std;

int main()
{
    priority_queue< int,vector<int>,greater<int> >q;
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int a;
        cin>>a;
        q.push(a);
    }
    int sum=0;
    while(q.size()>1)
    {
        int a=q.top();q.pop();
        int b=q.top();q.pop();
        sum+=a+b;
        q.push(a+b);
    }
    cout<<sum;
    return 0;
}
I.cpp

J.4992

n次移动,(0,0)朝北出发,每次走ai步,走完后右转,如果路径冲突,输出移动了几次,否则输出OK。

首先几何知识判断两条线段是否相交或重叠。

通过观察发现当前这条线段最多和前面8条线段存在冲突。

#include <cstdio>
#include <algorithm>
using namespace std;
 
const int MAX = 1000007, dx[] = { 0, 1, 0, -1 }, dy[] = { 1, 0, -1, 0 };
int N, a[MAX];
 
struct Point
{
    int x, y;
    Point(int _x = 0, int _y = 0) :
        x(_x), y(_y) {}
} points[MAX];
 
// true, if intervals [a,b] and [c,d] have non-empty intersection
bool overlap(int a, int b, int c, int d)
{
    if (a > b) swap(a, b);
    if (c > d) swap(c, d);
    return !(b < c || d < a);
}
 
// true if line segments [a1,a2] and [b1,b2] have non-empty intersection
bool intersect(Point a1, Point a2, Point b1, Point b2)
{
    bool is_vertical_a = (a1.x == a2.x), is_vertical_b = (b1.x == b2.x);
    if (is_vertical_a && is_vertical_b)
        return a1.x == b1.x && overlap(a1.y, a2.y, b1.y, b2.y);
    if (!is_vertical_a && !is_vertical_b)
        return a1.y == b1.y && overlap(a1.x, a2.x, b1.x, b2.x);
    // make a horizontal and b vertical
    if (is_vertical_a)
    {
        swap(a1, b1);
        swap(a2, b2);
    }
    return !(
        max(a1.x, a2.x) < b1.x ||
        min(a1.x, a2.x) > b1.x ||
        max(b1.y, b2.y) < a1.y ||
        min(b1.y, b2.y) > a1.y);
}
 
int solve()
{
    int x = 0, y = 0;
    for (int i = 0; i < N; ++i)
    {
        x += dx[i & 3] * a[i];
        y += dy[i & 3] * a[i];
        points[i + 1].x = x;
        points[i + 1].y = y;
        for (int j = max(0, i - 8); j < i - 2; ++j)
        if (intersect(points[j], points[j + 1], points[i], points[i + 1]))
            return i;
    }
    return -1;
}
 
int main()
{
    while (scanf("%d", &N) == 1)
    {
        for (int i = 0; i < N; ++i)
            scanf("%d", a + i);
        int result = solve();
        if (result == -1)
            printf("OK\n");
        else
            printf("%d\n", result);
    }
 
    return 0;
}
J.cpp

K.4541

n个数,求插入个数最少的整数,使其成为一个回文数列。

dp,答案是n-最长回文子序列的长度。

设字符串为s,f(i,j)表示s[i..j]的最长回文子序列。 

状态转移方程如下: 

当i>j时,f(i,j)=0。 

当i=j时,f(i,j)=1。 

当i<j并且s[i]=s[j]时,f(i,j)=f(i+1,j-1)+2。 

当i<j并且s[i]≠s[j]时,f(i,j)=max( f(i,j-1), f(i+1,j) )。 

由于f(i,j)依赖i+1,所以循环计算的时候,第一维必须倒过来计算,从s.length()-1到0。 

最后,s的最长回文子序列长度为f(0, s.length()-1)。

可以发现计算第i行时只用到了第i+1行,所以可以滚动数组减少内存使用。

#include<bits/stdc++.h>
using namespace std;
const int N=10005;
int a[N],n,dp[2][N];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(dp,0,sizeof dp);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        int cnt=0;
        for(int i=n;i>=1;i--)
        {
            cnt^=1;
            memset(dp[cnt],0,sizeof dp[cnt]);
            dp[cnt][i]=1;
            for(int j=i+1;j<=n;j++)
            {
                if(a[i]==a[j]) dp[cnt][j]=dp[cnt^1][j-1]+2;
                else dp[cnt][j]=max(dp[cnt][j-1],dp[cnt^1][j]);
            }
        }
        printf("%d\n",n-dp[cnt][n]);
    }
    return 0;
}
K.cpp

L.4561

n个人,1号为Sheldon,已知其余n-1个人投给了f[i]要买通需要花费c[i],1号需要投给1个人。最后1想要花最少的钱使得自己的票数>其他所有人的票数,求最少的钱。

贪心+讨论

这里每个人票数为p[i]。

1投给目前票数最少的人(好好思考思考),然后考虑1需要x票能赢,那么其余人i只要p[i]>=x就需要买通p[i]-x+1个人,肯定买最便宜的,最后如果1还差k票,那么把所有没买通的人按c[i]排序再取k个最小。

#include<bits/stdc++.h>
using namespace std;
vector<int>vec[105];
int f[105],c[105],t,a;
int main()
{
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)vec[i].clear();
        for(int i=2;i<=n;i++)cin>>f[i];
        for(int i=2;i<=n;i++)cin>>c[i];
        for(int i=2;i<=n;i++)vec[f[i]].push_back(c[i]);
        for(int i=1;i<=n;i++)sort(vec[i].begin(),vec[i].end());
        int M_P=1e9,M_POS=1;
        for(int i=2;i<=n;i++)
        {
            if((int)vec[i].size()<M_P)
            {
                M_P=(int)vec[i].size();
                M_POS=i;
            }
        }
        int sl=0;
        for(int i=1;i<=n;i++)if((int)vec[i].size()==M_P)sl++;
        if(sl==n)
        {
            int Minn=1e9,Minnp=1;
            for(int i=2;i<=n;i++)if((int)vec[i].size()>0&&vec[i][0]<Minn)Minn=vec[i][0],Minnp=i;
            vec[Minnp].push_back(0x3f3f3f3f);
        }
        else vec[M_POS].push_back(0x3f3f3f3f);
        int Min=1e9;
        for(int i=(int)vec[1].size();i<n;i++)
        {
            vector<int>prem[105],prr;
            int NEED=i-(int)vec[1].size();
            for(int j=2;j<=n;j++)prem[j]=vec[j];
            int sum=0;
            for(int j=2;j<=n;j++)
            {
                if((int)prem[j].size()>=i)
                {
                    int need=(int)prem[j].size()-i+1;
                    NEED-=need;
                    if(NEED<0)goto e;
                    for(int k=0;k<need;k++)sum+=prem[j][k];
                    for(int k=need;k<(int)prem[j].size();k++)prr.push_back(prem[j][k]);
                }
                else
                {
                    for(int k=0;k<(int)prem[j].size();k++)
                        prr.push_back(prem[j][k]);
                }
            }
            if(NEED>0)
            {
                sort(prr.begin(),prr.end());
                for(int j=0;j<NEED;j++)sum+=prr[j];
            }
            Min=min(Min,sum);
            e:;
        }
        cout<<Min<<endl;
    }
    return 0;
}
L.cpp

M.2337

已知Dick12岁,janepuff和spot相差s岁,yertle和puff相差p岁,yertle和spot相差y岁,Spot, Puff, Yertle和等于Dick,jane和,求Spot, Puff, Yertle的岁数。

那么由确定关系,设yertle为x岁,那么spot为x + y, puff为x + p然后与s进行比较。

#include<bits/stdc++.h>
using namespace std;

int main()
{
    int n,s,p,y,t;
    cin>>n;
    while(n--)
    {
        cin>>s>>p>>y>>t;
        int sum=12+t;
        int temp=sum-y-p;
        int x=temp/3;
        if(temp%3==0)
            cout<<x+y<<" "<<x+p<<" "<<x<<endl;
        else if(temp%3==1)
        {
            if(s+p==y)
                cout<<x+y+1<<" "<<x+p<<" "<<x<<endl;
            else
                cout<<x+y<<" "<<x+p+1<<" "<<x<<endl;
        }
        else
            cout<<x+y+1<<" "<<x+p+1<<" "<<x<<endl;
    }
    return 0;
}
M.cpp

猜你喜欢

转载自www.cnblogs.com/taozi1115402474/p/10851429.html
今日推荐