Codeforces Round #438 (Div. 1 + Div. 2 combined)(除G)解题报告

这场梁大大怎么就用我小号打了啊??
然后就2个小时出场?然后rank15涨飞?
(dlsFST好惨啊)

Bark to Unlock

搞笑题,记得考虑原来就出现就不会FST。

#include <bits/stdc++.h>
#define gc getchar()
#define ll long long
using namespace std;
char a[2],b[2];
int n,num[1000][2];
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-'0';
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
    return x*s;
}
int main()
{
    a[0]=gc,a[1]=gc;
    n=read();
    for (int i=1;i<=n;i++)
    {
        while (b[0]=gc,b[0]<'a'||b[0]>'z');
        b[1]=gc;
        if (b[0]==a[0]&&b[1]==a[1])
        {
            puts("YES");
            return 0;
        }
        num[b[0]][0]++,num[b[1]][1]++;
    }
    if (num[a[0]][1]&&num[a[1]][0]) puts("YES");
    else puts("NO");
    return 0;
}

Race Against Time

一百种方法的题目。

#include <bits/stdc++.h>
#define gc getchar()
#define ll long long
using namespace std;
double a[3];
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-'0';
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
    return x*s;
}
int main()
{
    int h,m,s,t1,t2;
    h=read(),m=read(),s=read(),t1=read(),t2=read();
    a[0]=(double)(h%12)+(double)m/60.0+(double)s/3600.0;
    a[1]=(double)m/5.0+(double)s/300.0;
    a[2]=(double)s/5.0;
    sort(a,a+3);
    if (t1>a[0]&&t1<a[1])
    {
        if (t2>a[0]&&t2<a[1]) puts("YES");
        else puts("NO");
    }
    if (t1>a[1]&&t1<a[2])
    {
        if (t2>a[1]&&t2<a[2]) puts("YES");
        else puts("NO");
    }
    if (t1<a[0]||t1>a[2])
    {
        if (t2<a[0]||t2>a[2]) puts("YES");
        else puts("NO");
    }
    return 0;
}

Qualification Rounds

似乎总共就最多16种。dfs似乎就好了。(小猫代码)

#include <bits/stdc++.h>
#define gc getchar()
#define ll long long
using namespace std;
int f[2][2][2][2],n,k,a[5],u[5],v[5],flag;
void dfs(int x)
{
    if (x==5)
    {
        if (f[u[1]][u[2]][u[3]][u[4]]&&f[v[1]][v[2]][v[3]][v[4]])
            flag=1;
        return;
    }
    for (int i=0;i<=1;i++)
        for (int j=0;j<=1;j++)
            if (i+j!=2)
            {
                u[x]=i,v[x]=j;
                dfs(x+1);
            }
}
int main()
{
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=4;j++)
        {
            if (j<=k) scanf("%d",&a[j]);
            else a[j]=0;
        }
        f[a[1]][a[2]][a[3]][a[4]]=1;
    }
    dfs(1);
    puts(flag?"YES":"NO");
}

Huge Strings

答案最多8(应该挺好证)。然后就只要维护前后8个就好。

#include <bits/stdc++.h>
#define gc getchar()
#define ll long long
#define N 109
#define M 8
using namespace std;
bitset<1<<M> pd[N<<1][M+1];
int n,m,l[N<<1][M+1],r[N<<1][M+1],len[N<<1],b[N],ret;
char str[N];
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-'0';
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
    return x*s;
}
int main()
{
    n=read();
    for (int i=1;i<=n;i++)
    {
        scanf("%s",str+1);
        len[i]=strlen(str+1);
        for (int j=1;j<=M;j++)
        {
            if (len[i]<j) break;
            int now=0;
            for (int k=1;k<j;k++) now=now<<1|(str[k]-'0');
            for (int k=j;k<=len[i];k++)
            {
                now=(now<<1|(str[k]-'0'))&((1<<j)-1);
                pd[i][j][now]=1;
            }
        }
        for (int j=1;j<=min(len[i],M);j++)
            l[i][j]=(str[j]-'0'),r[i][j]=(str[len[i]-j+1]-'0');
    }
    m=read();
    while (m--)
    {
        int x=read(),y=read(),L=0;
        for (int j=min(len[x],M);j;j--)
            b[++L]=r[x][j];
        for (int j=1;j<=min(len[y],M);j++)
            b[++L]=l[y][j];
        assert(L<=2*M);
        len[++n]=len[x]+len[y],ret=0;
        if (len[x]>M||len[y]>M||len[n]>M) len[n]=M+1;
        if (len[n]<=M)
            for (int i=1;i<=L;i++)
                l[n][i]=b[i],r[n][i]=b[L-i+1];
        else
        {
            for (int i=1;i<=min(len[x],M);i++)
                l[n][i]=l[x][i];
            if (len[x]<M)
                for (int i=len[x]+1;i<=M;i++)
                    l[n][i]=l[y][i-len[x]];
            for (int i=1;i<=min(len[y],M);i++)
                r[n][i]=r[y][i];
            if (len[y]<M)
                for (int i=len[y]+1;i<=M;i++)
                    r[n][i]=r[x][i-len[y]];
        }
        for (int i=1;i<=M;i++)
        {
            pd[n][i]=pd[x][i]|pd[y][i];
            if (L<i) continue;
            int now=0;
            for (int k=1;k<i;k++) now=now<<1|b[k];
            for (int k=i;k<=L;k++)
            {
                now=(now<<1|b[k])&((1<<i)-1);
                assert(now<(1<<i));
                pd[n][i][now]=1;
            }
        }
        for (int i=1;i<=M;i++)
        {
            bool flag=((int)pd[n][i].count()==(1<<i));
            if (flag) ret=i;
            else break;
        }
        printf("%d\n",ret);
    }
    return 0;
}

Policeman and a Tree

dp[x][y][z][w] 表示从 y 走到x y 这边剩下z个点, x 这边剩下w个点的最短距离,枚举第一条边,记忆化搜索即可。

#include <bits/stdc++.h>
#define gc getchar()
#define ll long long
#define N 59
#define inf 0x3f3f3f3f
using namespace std;
int n,first[N],number,st,tg[N],m,fa[N],d[N],f[N][N];
int DP[N][N][N][N],Ans=inf;
struct edge
{
    int to,next,val;
    void add(int x,int y,int z)
    {
        to=y,next=first[x],first[x]=number,val=z;
    }
}e[N<<1];
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-'0';
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
    return x*s;
}
int dp(int x,int y,int z,int w)
{
    if (z==0&&w==0) return 0;
    if (DP[x][y][z][w]) return DP[x][y][z][w];
    if (d[x]==1)
    {
        if (z==0) return 0;
        return DP[x][y][z][w]=dp(y,x,0,z)+f[x][y];
    }
    int g[N];
    for (int i=1;i<=w;i++) g[i]=-inf;
    g[0]=inf;
    for (int i=first[x];i;i=e[i].next)
        if (e[i].to!=y)
        {
            for (int j=w;j;j--)
                for (int k=1;k<=j;k++)
                    g[j]=max(g[j],min(g[j-k],dp(e[i].to,x,z+w-k,k)+e[i].val));
        }
    return DP[x][y][z][w]=g[w];
}
void dfs(int x)
{
    for (int i=first[x];i;i=e[i].next)
        if (e[i].to!=fa[x])
        {
            fa[e[i].to]=x,dfs(e[i].to);
            tg[x]+=tg[e[i].to];
        }
}
int main()
{
    n=read();
    for (int i=1;i<n;i++)
    {
        int x=read(),y=read(),z=read();
        e[++number].add(x,y,z);
        e[++number].add(y,x,z);
        d[x]++,d[y]++;
        f[x][y]=f[y][x]=z;
    }
    st=read(),m=read();
    for (int i=1;i<=m;i++) tg[read()]++;
    dfs(1);
    for (int i=first[st];i;i=e[i].next)
        if (e[i].to==fa[st]) Ans=min(Ans,dp(e[i].to,st,tg[st],m-tg[st])+e[i].val);
        else Ans=min(Ans,dp(e[i].to,st,m-tg[e[i].to],tg[e[i].to])+e[i].val);
    printf("%d\n",Ans);
    return 0;
}

Yet Another Minimization Problem

首先 dp[i][j] 表示前 j 个数分成i段的最小代价。
显然具有决策单调性。
k 层dp,考虑solve(l,r,L,R)表示这一层的 dp[now][l]dp[now][r] 的决策点在上一层的 dp[last][L]dp[last][R] 之间,如果按一般方式寻找 mid=l+r2 的决策点,递归,某一段数的代价比较难算,考虑类似 bfs 按层 solve 下去,每一层类似莫队的方法移动两端点,显然每层最多移动 O(n) 次,所以总时间复杂度 O(knlogn)

#include <bits/stdc++.h>
#define gc getchar()
#define ll long long
#define N 100009
#define inf (ll)0x3f3f3f3f3f3f3f3f
using namespace std;
ll n,k,a[N],dp[2][N],num[N],Ans,l=0,r=0;
struct node
{
    ll l,r,x,y;
    node(ll l=0,ll r=0,ll x=0,ll y=0):l(l),r(r),x(x),y(y){}
}q[N];
ll read()
{
    ll x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    ll s=ch-'0';
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
    return x*s;
}
void add(ll x)
{
    Ans+=(num[x]++);
}
void del(ll x)
{
    Ans-=(--num[x]);
}
ll get(ll x,ll y)
{
    while (r<y) add(a[++r]);
    while (l>x) add(a[--l]);
    while (r>y) del(a[r--]);
    while (l<x) del(a[l++]);
    return Ans+dp[0][x-1];
}
void solve()
{
    ll L=1,R=1;
    q[1]=node(1,n,1,n);
    while (L<=R)
    {
        node now=q[L++];
        ll mid=(now.l+now.r)>>1,m=now.x;
        for (ll i=now.x;i<=now.y&&i<=mid;i++)
        {
            ll tmp=get(i,mid);
            if (tmp<dp[1][mid]) dp[1][mid]=tmp,m=i;
        }
        if (now.l<mid) q[++R]=node(now.l,mid-1,now.x,m);
        if (mid<now.r) q[++R]=node(mid+1,now.r,m,now.y);
    }
}
int main()
{
    n=read(),k=read();
    for (ll i=1;i<=n;i++) a[i]=read();
    memset(dp,inf,sizeof(dp));
    dp[1][0]=0;
    for (ll t=1;t<=k;t++)
    {
        for (ll i=0;i<=n;i++) dp[0][i]=dp[1][i];
        memset(num,0,sizeof(num)),Ans=r=0,l=1;
        solve();
    }
    printf("%lld\n",dp[1][n]);
    return 0;
}

(G题似乎策略可以想到,然而完全不会写啊。有空再补吧)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值