USACO 2017 January Contest总结

比赛链接

T1 Balanced Photo

题目链接

题目大意:一个人要给他的一堆牛拍照,每头牛有一个身高且身高互不相同。定义 L [ i ] 为第 i 头牛左边比它高的牛的个数, R [ i ] 为第 i 头牛右边比它高的牛的个数,定义“不平衡的牛”:它的 L [ i ] , R [ i ] 相差两倍以上,求不平衡的牛的个数。

思路:以下是刚看到题的时候的心理活动
- 大概就是查询一个数前面有几个数比他大。
- 也就是查询一个数的排名。
- 为什么不用set啊
- set查不了排名啊
- 那我就手写平衡树吧。

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<cctype>
#define pa pair<int,int>
#define INF 0x3f3f3f3f
#define inf 0x3f
#define fi first
#define se second
#define mp make_pair
#define ll long long
#define ull unsigned long long
#define pb push_back

using namespace std;

inline ll read()
{
    long long f=1,sum=0;
    char c=getchar();
    while (!isdigit(c)) {if (c=='-') f=-1;c=getchar();}
    while (isdigit(c)) {sum=sum*10+c-'0';c=getchar();}
    return sum*f;
}
const int MAXN=100010;
int ch[MAXN][2],fa[MAXN],sz[MAXN],val[MAXN],root,cnt,t[MAXN];
int son(int x){return x==ch[fa[x]][1];}
int update(int x){sz[x]=sz[ch[x][1]]+sz[ch[x][0]]+t[x];}
void rotate(int x)
{
    int y=fa[x],z=fa[y],b=son(x),c=son(y);
    ch[z][c]=x,fa[x]=z;
    if (ch[x][!b]) fa[ch[x][!b]]=y;
    ch[y][b]=ch[x][!b],ch[x][!b]=y,fa[y]=x;
    update(y),update(x);
}
void splay(int x,int p)
{
    while (fa[x]!=p)
    {
        int y=fa[x],z=fa[y];
        if (z==p) rotate(x);
        else
        {
            if (son(x)!=son(y))
                rotate(x),rotate(x);
            else
                rotate(y),rotate(x);
        }
    }
    if (!fa[x]) root=x;
}
int find_qq(int x)
{
    int now=root,ans=0;
    while (now)
    {
        if (val[now]<x)
            ans=now,now=ch[now][1];
        else
            now=ch[now][0];
    }
    return ans;
}
int find_hj(int x)
{
    int now=root,ans=0;
    while (now)
    {
        if (val[now]>x)
            ans=now,now=ch[now][0];
        else
            now=ch[now][1];
    }
    return ans;
}
void insert(int x)
{
    int qq=find_qq(x),hj=find_hj(x);
    splay(qq,0),splay(hj,qq);
    int y=ch[hj][0];
    if (y) t[y]++,update(y);
    else ch[hj][0]=++cnt,val[cnt]=x,sz[cnt]=1,fa[cnt]=hj,t[cnt]=1,splay(cnt,0);
}
int query_upper(int x)
{
    int now=root,ans=0;
    while (now)
    {
        if (x>val[now])
            now=ch[now][1];
        else
        {
            ans+=sz[ch[now][1]];
            if (x==val[now]) return ans;
            ans+=t[now];
            now=ch[now][0]; 
        }
    }
}
void init()
{
    memset(sz,0,sizeof(sz)),memset(t,0,sizeof(t));
    memset(ch,0,sizeof(ch)),memset(fa,0,sizeof(fa));
    memset(val,0,sizeof(val));
    val[1]=1e9,val[2]=-1e9;
    fa[2]=1,root=1,cnt=2,ch[1][0]=2;
}
int a[MAXN],l[MAXN],r[MAXN];
int main()
{
    int n;
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    init();
    for (int i=1;i<=n;i++)
    {
        insert(a[i]);
        l[i]=query_upper(a[i]);
    }
    init();
    for (int i=n;i>=1;i--)
    {
        insert(a[i]);
        r[i]=query_upper(a[i]);
    }
    int ans=0;
    for (int i=1;i<=n;i++)
        if (min(l[i],r[i])*2<max(l[i],r[i]))
            ans++;
    cout<<ans;
    return 0;
}

后来发现只需要一个求逆序对的东西,所以写了权值线段树。

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<cctype>
#define pa pair<int,int>
#define INF 0x3f3f3f3f
#define inf 0x3f
#define fi first
#define se second
#define mp make_pair
#define ll long long
#define ull unsigned long long
#define pb push_back

using namespace std;

inline ll read()
{
    long long f=1,sum=0;
    char c=getchar();
    while (!isdigit(c)) {if (c=='-') f=-1;c=getchar();}
    while (isdigit(c)) {sum=sum*10+c-'0';c=getchar();}
    return sum*f;
}
const int MAXN=100010;
int f[4*MAXN];
void update(int root,int left,int right,int x)
{
    if (left==right)
    {
        f[root]++;
        return ;
    }
    int mid=(left+right)>>1;
    if (x<=mid)
        update(2*root,left,mid,x);
    else
        update(2*root+1,mid+1,right,x);
    f[root]=f[2*root]+f[2*root+1];
}
int query(int root,int left,int right,int qleft,int qright)
{
    if (qleft<=left && qright>=right)
        return f[root];
    int mid=(left+right)>>1;
    if (qright<mid)
        return query(2*root,left,mid,qleft,qright);
    else if (qleft>mid)
        return query(2*root+1,mid+1,right,qleft,qright);
    else
    {
        int ans1,ans2;
        ans1=query(2*root,left,mid,qleft,mid);
        ans2=query(2*root+1,mid+1,right,mid+1,qright);
        return ans1+ans2;
    }
}
int a[MAXN],l[MAXN],r[MAXN];
vector <int> v;
int main()
{
    int n;
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]),v.push_back(a[i]);
    sort(v.begin(),v.end());
    for (int i=1;i<=n;i++)
        a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin()+1;
    for (int i=1;i<=n;i++)
    {
        l[i]=query(1,1,n,a[i]+1,n);
        update(1,1,n,a[i]);
    }
    memset(f,0,sizeof(f));
    for (int i=n;i>=1;i--)
    {
        r[i]=query(1,1,n,a[i]+1,n);
        update(1,1,n,a[i]);
    }
    int ans=0;
    for (int i=1;i<=n;i++)
        if (min(l[i],r[i])*2<max(l[i],r[i]))
            ans++;
    cout<<ans;
    return 0;
}

T2 Hoof, Paper, Scissors

题目链接

题目大意:你在玩石头剪子布,你已知你的对手的出招顺序,你一开始会出石头,然后一直保持一个手势出下去,你可以改变K次手势,问你最多赢几次。

思路:算是比较简单的DP。
f [ i ] [ j ] [ 1 / 2 / 3 ] 表示前i轮变换j次手势最多赢几次,你现在的手势是什么。预处理出一直不变能赢几次。先枚举第二维,再枚举第一维。转移即可。
因为把一个2打成了1所以WA了两发。。

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<cctype>
#define pa pair<int,int>
#define INF 0x3f3f3f3f
#define inf 0x3f
#define fi first
#define se second
#define mp make_pair
#define ll long long
#define ull unsigned long long
#define pb push_back

using namespace std;

inline ll read()
{
    long long f=1,sum=0;
    char c=getchar();
    while (!isdigit(c)) {if (c=='-') f=-1;c=getchar();}
    while (isdigit(c)) {sum=sum*10+c-'0';c=getchar();}
    return sum*f;
}
const int MAXN=100010;
const int MAXK=22;
const int SET=4;
int f[MAXN][MAXK][SET];
int a[MAXN];
int win(int x,int y)
{
    if (x==1 && y==2) return 1;
    else if (x==2 && y==3) return 1;
    else if (x==3 && y==1) return 1;
    else return 0;
}
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++)
    {
        char s[10];
        scanf("%s",s+1);
        if (s[1]=='H') a[i]=1;
        else if (s[1]=='S') a[i]=2;
        else a[i]=3;
    }
    for (int i=1;i<=n;i++)
    {
        f[i][0][1]=f[i-1][0][1]+win(1,a[i]);
        f[i][0][2]=f[i-1][0][2]+win(2,a[i]);
        f[i][0][3]=f[i-1][0][3]+win(3,a[i]);
    }
    for (int j=1;j<=k;j++)
    {
        for (int i=1;i<=n;i++)
        {
            f[i][j][1]=max(f[i-1][j][1],max(f[i-1][j-1][2],f[i-1][j-1][3]))+win(1,a[i]);
            f[i][j][2]=max(f[i-1][j][2],max(f[i-1][j-1][1],f[i-1][j-1][3]))+win(2,a[i]);
            f[i][j][3]=max(f[i-1][j][3],max(f[i-1][j-1][1],f[i-1][j-1][2]))+win(3,a[i]);
        }
    }
    int ans1=-1,ans2=-1,ans3=-1;
    for (int i=1;i<=n;i++)
    {
        ans1=max(ans1,f[n][k][1]);
        ans2=max(ans2,f[n][k][2]);
        ans3=max(ans3,f[n][k][3]);
    }
    cout<<max(ans1,max(ans2,ans3));
    return 0;
}

T3 Cow Navigation

题目链接

题目大意:一个 n × n 的网格,在 ( n , 1 ) 有两头牛,分别面向正上方和正右方,现在你要给他们两个同时发出指令“向前走”,“右转”或“左转”,两头牛会同时遵守这个指令。
地图上有一些不能去的格子,若你的指令让牛向无法到达的格子前进,他会自动忽略。
他们俩都要去 ( n , n ) ,若一头牛已经到达终点,他会忽略后面所有的指令,求想让两头牛都到达终点的最短指令是多段。

思路:BFS。
d i s [ x 1 ] [ y 1 ] [ x 2 ] [ y 2 ] [ d 1 ] [ d 2 ] 表示两头牛分别在 ( x 1 , y 2 ) , ( x 2 , y 2 ) ,面向 d 1 , d 2 的最少指令数。暴力转移分三种情况,前进,左转,右转。

WA了一次因为没看到这句话。
若一头牛已经到达终点,他会忽略后面所有的指令

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<cctype>
#define pa pair<int,int>
#define INF 0x3f3f3f3f
#define inf 0x3f
#define fi first
#define se second
#define mp make_pair
#define ll long long
#define ull unsigned long long
#define pb push_back

using namespace std;

inline ll read()
{
    long long f=1,sum=0;
    char c=getchar();
    while (!isdigit(c)) {if (c=='-') f=-1;c=getchar();}
    while (isdigit(c)) {sum=sum*10+c-'0';c=getchar();}
    return sum*f;
}
const int MAXN=25;
const int dx[5]={0,-1,0,1,0};
const int dy[5]={0,0,1,0,-1};
struct node
{
    int x1,y1,x2,y2,d1,d2;
    node (int x1,int y1,int x2,int y2,int d1,int d2):x1(x1),y1(y1),x2(x2),y2(y2),d1(d1),d2(d2) {}
    node () {}
};
int a[MAXN][MAXN],n;
queue <node> q;
bool visit[MAXN][MAXN][MAXN][MAXN][5][5];
int dis[MAXN][MAXN][MAXN][MAXN][5][5];
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        char s[MAXN];
        scanf("%s",s+1);
        for (int j=1;j<=n;j++)
            a[i][j]=s[j]=='E';
    }
    memset(dis,inf,sizeof(dis));
    dis[n][1][n][1][1][2]=0;
    q.push(node(n,1,n,1,1,2));
    visit[n][1][n][1][1][2]=1;
    while (!q.empty())
    {
        node x=q.front();
        int dist=dis[x.x1][x.y1][x.x2][x.y2][x.d1][x.d2];
//      cout<<x.x1<<' '<<x.y1<<' '<<x.x2<<' '<<x.y2<<' '<<x.d1<<' '<<x.d2<<' '<<dist<<endl;
        q.pop();
        int nx1,ny1,nx2,ny2,nd1,nd2;
        nx1=x.x1+dx[x.d1],ny1=x.y1+dy[x.d1];
        nx2=x.x2+dx[x.d2],ny2=x.y2+dy[x.d2];
        if (nx1>n || ny1>n || nx1<=0 || ny1<=0 || !a[nx1][ny1] || (x.x1==1 && x.y1==n)) nx1=x.x1,ny1=x.y1;
        if (nx2>n || ny2>n || nx2<=0 || ny2<=0 || !a[nx2][ny2] || (x.x2==1 && x.y2==n)) nx2=x.x2,ny2=x.y2;
        nd1=x.d1,nd2=x.d2;
        int &ndis1=dis[nx1][ny1][nx2][ny2][nd1][nd2];
        if (ndis1>dist+1)
        {
            ndis1=dist+1;
            if (!visit[nx1][ny1][nx2][ny2][nd1][nd2])
            {
                q.push(node(nx1,ny1,nx2,ny2,nd1,nd2));
                visit[nx1][ny1][nx2][ny2][nd1][nd2]=1;  
            }
        }
        nx1=x.x1,ny1=x.y1,nx2=x.x2,ny2=x.y2;
        nd1=x.d1-1,nd2=x.d2-1;
        if (!nd1) nd1=4;if (!nd2) nd2=4;
        int &ndis2=dis[nx1][ny1][nx2][ny2][nd1][nd2];
        if (ndis2>dist+1)
        {
            ndis2=dist+1;
            if (!visit[nx1][ny1][nx2][ny2][nd1][nd2])
            {
                q.push(node(nx1,ny1,nx2,ny2,nd1,nd2));
                visit[nx1][ny1][nx2][ny2][nd1][nd2]=1;  
            }
        }
        nd1=x.d1+1,nd2=x.d2+1;
        if (nd1==5) nd1=1;if (nd2==5) nd2=1;
        int &ndis3=dis[nx1][ny1][nx2][ny2][nd1][nd2];
        if (ndis3>dist+1)
        {
            ndis3=dist+1;
            if (!visit[nx1][ny1][nx2][ny2][nd1][nd2])
            {
                q.push(node(nx1,ny1,nx2,ny2,nd1,nd2));
                visit[nx1][ny1][nx2][ny2][nd1][nd2]=1;  
            }
        }
//      visit[x.x1][x.y1][x.x2][x.y2][x.d1][x.d2]=0;
    }
    int ans=INF;
    for (int i=1;i<=4;i++)
        for (int j=1;j<=4;j++)
            ans=min(ans,dis[1][n][1][n][i][j]);
    cout<<ans;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/szh_0808/article/details/80496668