2018湖南省多校第一场解题报告(CSU OJ)

A Artwork :并查集倒着推

//题目原型,删点之后图上还剩下多少个联通块
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int MAXM=11000;
const int MAXN=1100;
bool del[MAXN][MAXN];
int fa[MAXN*MAXN];
int find(int x)
{
    return fa[x]==-1?x:fa[x]=find(fa[x]);
}
bool unite(int a,int b)
{
    int t1=find(a),t2=find(b);
    if(t1==t2) return false;
    fa[t1]=t2;
    return true;
}
struct point_t
{
    int x,y;
    point_t() {}
    point_t(int _x,int _y):x(_x),y(_y) {}
};
struct line_t
{
    point_t a,b;
    line_t() {}
    line_t(point_t _a,point_t _b):a(_a),b(_b) {}
}question[MAXM];
vector<int> vec[MAXM];
const int L[]={1,0,-1,0};
const int R[]={0,1,0,-1};
int get_hashs(int x,int y,int n)
{
    x--,y--;
    return x*n+y;
}
int answer[MAXM];
int change(int x,int y,int n,int m)
{
    int ret=1;
    for(int i=0;i<4;i++)
    {
        int tempx=x+L[i],tempy=y+R[i];
        if(tempx<1||tempx>n||tempy<1||tempy>m||del[tempx][tempy]) continue;
        if(unite(get_hashs(x,y,m),get_hashs(tempx,tempy,m))) ret--;
    }
    return ret;
}
int main()
{
//    freopen("in.txt","r",stdin);
    int n,m,q;
    while(scanf("%d%d%d",&n,&m,&q)!=EOF)
    {
        for(int i=1;i<=1;i++)
            vec[i].clear();
        memset(fa,-1,sizeof(fa));
        memset(del,false,sizeof(del));
        for(int i=1;i<=q;i++)
        {
            int x1,y1,x2,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            question[i]=line_t(point_t(x1,y1),point_t(x2,y2));
        }
        //然后离线开始慢慢加边
        for(int i=1;i<=q;i++)
        {
            if(question[i].a.x==question[i].b.x)
            {
                int x=question[i].a.x;
                for(int j=question[i].a.y;j<=question[i].b.y;j++)
                {
                    if(del[x][j]) continue;
                    del[x][j]=true;
                    vec[i].push_back(j);
                }
            }
            else
            {
                int y=question[i].a.y;
                for(int j=question[i].a.x;j<=question[i].b.x;j++)
                {
                    if(del[j][y]) continue;
                    del[j][y]=true;
                    vec[i].push_back(j);
                }
            }
        }
//        for(int i=1;i<=q;i++)
//        {
//            printf("question :%d\n",i);
//            for(int j=0;j<vec[i].size();j++)
//                printf("%d ",vec[i][j]);
//            printf("\n")
//        }
        for(int i=1;i<=n;i++)
           for(int j=1;j<=m;j++)
            {
                if(del[i][j]) continue;
//                printf("No DEl :%d %d\n",i,j);
                for(int k=0;k<4;k++)
                {
                    int x=i+L[k],y=j+R[k];
                    if(x<1||x>n||y<1||y>m) continue;
                    if(del[x][y]) continue;
                    int new1=get_hashs(i,j,m);
                    int new2=get_hashs(x,y,m);
                    unite(new1,new2);
//                    printf("new1 :%d new2 :%d\n",new1,new2);
                }
            }
        int total=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                if(del[i][j]) continue;
                int hashed=get_hashs(i,j,m);
                if(fa[hashed]==-1) total++;
//                printf("hashed :(%d,%d) %d \n",i,j,fa[hashed]);
            }
        answer[q]=total;
        for(int i=q;i>=2;i--)
        {
            //然后加上删去的方块,看有多少个
            line_t line=question[i];
//            printf("(%d,%d)->(%d,%d)\n",line.a.x,line.a.y,line.b.x,line.b.y);
            int blocks=answer[i];
            if(line.a.x==line.b.x)
            {
                int x=line.a.x;
                for(int j=0;j<vec[i].size();j++)
                {
                    //如果这个方块已经被删去了,那么加上他
                    int mmp=vec[i][j];
                    if(del[x][mmp])
                    {
                        del[x][mmp]=false;
                        blocks+=change(x,mmp,n,m);
                    }
                }
                answer[i-1]=blocks;
            }
            else
            {
                int y=line.a.y;
                for(int j=0;j<vec[i].size();j++)
                {
                    int mmp=vec[i][j];
                    if(del[mmp][y])
                    {
                        del[mmp][y]=false;
                        int temp=change(mmp,y,n,m);
                        blocks+=temp;
                    }
                }
                answer[i-1]=blocks;
            }
        }
        for(int i=1;i<=q;i++)
            printf("%d\n",answer[i]);
    }
    return 0;
}

B Bless You Autocorrect! : 字典树+bfs(其实没必要用spfa求得最短路,因为每条边的距离都是1,所以bfs可以直接求得距离,qaq)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int SIZE=1111111;
struct node_t
{
    int son[28];
    int idx;
}node[SIZE];
//其中26记录的是fa节点,27记录的是tab节点
int toUsed;
char word[SIZE];
void init()
{
    toUsed=1;
    memset(node,-1,sizeof(node_t));
}
inline int _newnode()
{
    memset(node+toUsed,-1,sizeof(node_t));
    return toUsed++;
}
void insert(const char *str,int idx)
{
    int root=0;
    for(int i=0;str[i];i++)
    {
        int sn=str[i]-'a';
        if(node[root].son[sn]==-1) node[root].son[sn]=_newnode();
        node[node[root].son[sn]].son[26]=root;
        root=node[root].son[sn];
    }
    int cur=0;
    for(int i=0;str[i];i++)
    {
        int sn=str[i]-'a';
        cur=node[cur].son[sn];
        if(node[cur].son[27]==-1) node[cur].son[27]=toUsed-1;
    }
    node[root].idx=idx;
//    printf("Word :%s table[%d] :%d\n",word,idx,table[idx]);
}
//搜索每一个节点tab键后会跳转到哪里
//对于每个要查询的字符串,我们首先找到其能在字典树上匹配到的最大长度,其次然后做bfs求得最短距离
//记录0点到每一个点之间的最短距离
int dist[SIZE];
bool vis[SIZE];
void spfa(int s)
{
    memset(vis,false,sizeof(vis));
    memset(dist,0x3f,sizeof(dist));
    vis[s]=true;dist[s]=0;
    node[s].son[27]=-1;
    queue<int> que;
    while(!que.empty()) que.pop();
    que.push(s);
    while(!que.empty())
    {
        int u=que.front();
        que.pop();
        vis[u]=true;
        for(int i=0;i<28;i++)
        {
            if(node[u].son[i]==-1) continue;
            int v=node[u].son[i];
            if(dist[v]>dist[u]+1)
            {
                dist[v]=dist[u]+1;
//                if(v==7) printf("from %d -> %d :%d\n",u,v,dist[v]);
                if(!vis[v])
                {
                    vis[v]=true;
                    que.push(v);
                }
            }
        }
    }
}
int query(const char *str)
{
    //i记录能匹配到的最大长度
    int i,final_node=0;
    for(i=0;str[i];i++)
    {
        int sn=str[i]-'a';
        if(node[final_node].son[sn]==-1) break;
        final_node=node[final_node].son[sn];
    }
    //然后bfs求得从0点到final点的最短距离
    int lens=strlen(str);
//    printf("final_node :%d   %d + %d\n",final_node,dist[final_node],lens-i);
    return dist[final_node]+lens-i;
}
int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        for(int i=0;i<n;i++)
        {
            scanf("%s",word);
            insert(word,i);
        }
        spfa(0);
        for(int i=0;i<m;i++)
        {
            scanf("%s",word);
            int ans=query(word);
            printf("%d\n",ans);
        }
        printf("\n");
    }
    return 0;
}

C Card Hand Sorting :暴力枚举 + 最长公共子序列

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
//枚举((2^4)*4!)种排列组合,求得最少要移动多少次
const int MAXN=60;
struct pock_t
{
    int ranks;
    char suits;
    pock_t() {}
    pock_t(int _ranks,char _suits):ranks(_ranks),suits(_suits) {}
}pock[MAXN],temp[MAXN];
int trans(char x)
{
    if(x>='2'&&x<='9') return x-'0';
    else if(x=='T') return 10;
    else if(x=='J') return 11;
    else if(x=='Q') return 12;
    else if(x=='K') return 13;
    else return 14;
}
//然后爆搜加上枚举生成每种排列组合
const char suits[]={'s','h','d','c'};
char change[4];
int up_down[4];
bool vis[4];
int n,ans;
int find(char suit)
{
    for(int i=0;i<4;i++)
        if(change[i]==suit) return i;
    return -1;
}
bool cmp(const pock_t& a,const pock_t& b)
{
    //首先如果花色相同
    int fucka=find(a.suits),fuckb=find(b.suits);
    if(a.suits==b.suits)
    {
        if(up_down[fucka]==1) return a.ranks<b.ranks;
        else return a.ranks>b.ranks;
    }
    else return fucka<fuckb;
}
//记录最长上升子序列
int dp[MAXN][MAXN];
void solve()
{
    memcpy(temp,pock,sizeof(pock));
    sort(temp+1,temp+n+1,cmp);
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(pock[i].ranks==temp[j].ranks&&pock[i].suits==temp[j].suits)
                dp[i][j]=dp[i-1][j-1]+1;
            else dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
    ans=min(ans,n-dp[n][n]);
}
void dfs(int depth)
{
    if(depth==4) solve();
    else
    {
        for(int i=0;i<4;i++)
        {
            if(vis[i]) continue;
            vis[i]=true;
            up_down[depth]=1;
            change[depth]=suits[i];
            dfs(depth+1);
            up_down[depth]=-1;
            change[depth]=suits[i];
            dfs(depth+1);
            vis[i]=false;
        }
    }
}
int main()
{
//    freopen("in.txt","r",stdin);
    while(scanf("%d",&n)!=EOF)
    {
        char tra,suit;
        for(int i=1;i<=n;i++)
        {
            cin>>tra>>suit;
            pock[i]=pock_t(trans(tra),suit);
        }
        ans=0x3f3f3f3f;
        memset(vis,false,sizeof(vis));
        dfs(0);
        cout<<ans<<endl;
    }
    return 0;
}

D Daydreaming Stockbroker (dp)

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int MAXN=400;
LL dp[MAXN];
LL stock[MAXN];
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
            cin>>stock[i];
        dp[1]=100;
        //其实也可以选择一直不买,反正结果的时候比一比就知道了
        for(int i=2;i<=n;i++)
        {
//            puts("MMP");
            LL no_buy=0;
            for(int j=1;j<i;j++)
            {
                //其实也可以选择当天不买
                no_buy=max(no_buy,dp[j]);
                LL win=(stock[i]-stock[j]);
                if(win<0) continue;
                LL could_buy=dp[j]/stock[j];
                LL rem=dp[j]%stock[j];
                if(could_buy>100000)
                {
                    rem+=(could_buy-100000)*stock[j];
                    could_buy=100000;
                }
                dp[i]=max(dp[i],rem+stock[i]*(could_buy));
//                cout<<dp[i]<<endl;
            }
            dp[i]=max(no_buy,dp[i]);
//            printf("dp[%d] :%d\n",i,dp[i]);
        }
        cout<<dp[n]<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值