20160609常规赛总结

kao这场比赛也是醉了。
下午刚骑完环城晚上醉醺醺的。
敲完以后觉得感觉很好,就估分估了240
被小C严重鄙视说不可能
然后第一题爆0了==
现在说一下题目。

T1
模拟题,因为两句话写反了导致全部都T了。

T2

一道裸的前缀和优化dp
算了还是写的详细点吧==
Sources Codeforces 645 E

Description
给出长度为m的字符串以及k个小写字母,求再任意加上n个字符(在k的范围内)总串不同子序列的个数的最大值。
注意:空串也计 入统计。

Solution
定义dp[i]表示以str[i]为结尾的与之前的不同子序列的个数
那么转移的时候只要转移到之前相同处即可。
然后ans= n+mi=1 dp[i]
为了让ans最大我们最好最大化dp[i]
然后转移的时候dp[i]= i1i=last[str[i]] dp[i]
最大化的dp[i]也可以同时最大化后面的dp值。
关于后面的n个字母,由于转移方程一定,我们希望让last[str[i]]尽量小就好了。
作为全场唯一个A掉的现在想来还有点小激动。。
虽然它是前缀和优化dp的裸体。

T3

Sources Codeforces 152E(有改编)

Description
给定一个n*m的矩阵,以及k个坐标,求包含k个坐标的的四联通块的点的权值的最小值。

Solution
这题给了很多的水分点。最小最简单的那个挂了==
现在一万个不爽。。整整少了10分==
表程是所谓状压dp
这个dp是用填表(坑)法来实现的。
首先我们令dp[i][j][S]表示点(i,j)覆盖状态为S的最小点权和。
它可以向四周填坑。
可以自己填自己,当然这要有个前提就是刚好自己里有一个状态覆盖和当前没有交集。
这样的状态好像很乱。
瞎逼跑个最短路就好了。。

放个源代码

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
const int M=105;
const int Ss=1<<8;
const int INF=1<<30;
int dp[M][M][Ss],A[M][M],n,m,k,mx,my,ans;
bool mark[M][M][Ss];
struct node{int x,y;}c[M];
struct status{
    int x,y,S,dis;
    inline bool operator < (const status &tmp)const{
        return dis>tmp.dis;
    }
};
int rx[]={0,1,0,-1};
int ry[]={1,0,-1,0};
priority_queue<status>que;
inline void Min(int &a,int b){if(a>b)a=b;}
inline bool check(const int &x,const int &y){return x>0&&x<=n&&y>0&&y<=m;}
inline void bfs(){
    ans=INF;
    memset(dp,127,sizeof(dp));
    for(int i=0;i<=k;++i)
        que.push((status){c[i].x,c[i].y,1<<i,dp[c[i].x][c[i].y][1<<i]=0});
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            que.push((status){i,j,0,dp[i][j][0]=0});
    for(;!que.empty();){
        status v=que.top();que.pop();
        int x=v.x,y=v.y,S=v.S,dis=v.dis,dist=dis+A[x][y];
        if(mark[x][y][S])continue;
        mark[x][y][S]=1;
        for(int i=0;i<4;++i){
            int nx=x+rx[i],ny=y+ry[i];
            if(!check(nx,ny))continue;
            if(dist<dp[nx][ny][S])que.push((status){nx,ny,S,dp[nx][ny][S]=dist});
        }
        for(int St=0;St<1<<k+1;++St){
            if(St&S||!mark[x][y][St])continue;
            int tS=St|S,val=dis+dp[x][y][St];
            if(val<dp[x][y][tS]){
                que.push((status){x,y,tS,dp[x][y][tS]=val});
            }
        }
    }
    int S=0;
    for(int i=0;i<=k;++i)S|=1<<i;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            Min(ans,dp[i][j][S]+A[i][j]);
    ans-=A[c[0].x][c[0].y];
}
int main(){
    cin>>n>>m>>k;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            scanf("%d",A[i]+j);
    for(int i=0;i<=k;++i)
        scanf("%d %d",&c[i].x,&c[i].y);
    bfs();
    cout<<ans<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值