NOIP2017普及组解题报告

T1:。。略
T2:。。。略
T3:。。。。还是说一下吧。
分类讨论写个搜索,剪下枝,也很水。。

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

const int MAXN=1e2+5;

int ma[MAXN][MAXN];//-1无色 0红色 1黄色 
int ans[MAXN][MAXN];
int fx[]={1,-1,0,0},fy[]={0,0,1,-1}; 
int n,m;



void dfs(int x,int y,int c,int use){//use 0当前格没用 1用了魔法 
    for(int i=0;i<4;i++){
        if(x+fx[i]<1||x+fx[i]>m||y+fy[i]<1||y+fy[i]>m)continue;
        if(!use){
            if(ma[x+fx[i]][y+fy[i]]==c&&ans[x+fx[i]][y+fy[i]]>ans[x][y]){
                ans[x+fx[i]][y+fy[i]]=ans[x][y];
                dfs(x+fx[i],y+fy[i],c,0);   
            }
            if(ma[x+fx[i]][y+fy[i]]!=c&&ma[x+fx[i]][y+fy[i]]!=-1&&ans[x+fx[i]][y+fy[i]]>ans[x][y]+1){
                ans[x+fx[i]][y+fy[i]]=ans[x][y]+1;
                dfs(x+fx[i],y+fy[i],c^1,0);
            }
            if(ma[x+fx[i]][y+fy[i]]==-1&&ans[x+fx[i]][y+fy[i]]>ans[x][y]+2){
                ans[x+fx[i]][y+fy[i]]=ans[x][y]+2;
                dfs(x+fx[i],y+fy[i],c,1);
            }   
        }
        else{
            if(ma[x+fx[i]][y+fy[i]]!=-1&&ma[x+fx[i]][y+fy[i]]==c&&ans[x+fx[i]][y+fy[i]]>ans[x][y]){
                ans[x+fx[i]][y+fy[i]]=ans[x][y];
                dfs(x+fx[i],y+fy[i],c,0);
            }
            if(ma[x+fx[i]][y+fy[i]]!=-1&&ma[x+fx[i]][y+fy[i]]!=c&&ans[x+fx[i]][y+fy[i]]>ans[x][y]+1){
                ans[x+fx[i]][y+fy[i]]=ans[x][y]+1;
                dfs(x+fx[i],y+fy[i],c^1,0);
            }
        }
    }
}

int main(){
    memset(ma,-1,sizeof(ma));
    memset(ans,0x7f,sizeof(ans));
    scanf("%d%d",&m,&n);
    for(int i=1;i<=n;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        ma[x][y]=z;
    }
    ans[1][1]=0;
    dfs(1,1,ma[1][1],0);
    if(ans[m][m]!=2139062143)printf("%d\n",ans[m][m]);
    else printf("-1\n");
    return 0;
}

T4:看到题,最暴力的方法:直接枚举金币去搜索。
如何优化?首先看到一段单调区间,我们可以二分答案。这样可以拿到50分。
100分:我们发现位置也是连续递增的,并且50分做法的状态转移方程是
f【i】=max(f【j】)+w【i】。(0<=j<i) 形如这样的状态转移方程,我们如果循环查找f【j】显然会重复。如何不重复呢?用单调队列去优化。实现一个队列,随时可以O(1)查询队列中最大(最小)元素。
可以用STL中2个deque来实现(常数大)qaq 用STLdeque在洛谷上被卡成90分,计蒜客AC。
这样转移的时候,维护单调队列可以随时查询最大的f【j】。每次Dp是O(n)复杂度,整体复杂度O(log(ans)n)

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

#define ll long long

const ll MAXN=5e5+100;
const ll INF=(1ll<<60);
ll n,d,k;
ll pos[MAXN],w[MAXN],f[MAXN];
bool flag=0;

struct mque{
    deque<ll>m,q;
    inline void push(ll x){
        q.push_back(x);
        while(m.size()&&m.back()<x)m.pop_back();
        m.push_back(x);
    }
    inline void pop(){
        ll x=q.front();
        q.pop_front();
        if(x==m.front())m.pop_front();
    }
    inline ll top(){
        return m.front();
    }
    inline ll size(){
        return m.size();
    }
}mq;

bool check(ll minn,ll maxx,ll df){
    while(mq.size())mq.pop();
    memset(f,0,sizeof(f));
    f[0]=0;
    ll l=0,r=0;
    for(int i=1;i<=n;i++){//    cout<<i<<"ok"<<endl;
        while(pos[i]-pos[l]>=minn){
            mq.push(f[l]);l++;
        }
        while(pos[i]-pos[r]>maxx){
            r++;mq.pop();
        }
        if(!mq.size())f[i]=-INF;
        else{
            f[i]=mq.top()+w[i];//cout<<endl;cout<<f[i]<<endl;
        //  cout<<i<<" "<<f[i]<<endl;
            if(f[i]>=df){
                flag=1;return 1;    
            }
        }
    }
    return 0;
}

int main(){
    scanf("%lld%lld%lld",&n,&d,&k);
    for(ll i=1;i<=n;i++){
        scanf("%lld%lld",&pos[i],&w[i]);
    }
    ll l=0,r=pos[n];
    while(l+1!=r){
        ll mid=(l+r)>>1;
    //  cout<<"mid:"<<mid<<endl;
        ll xiao=d-mid,da=d+mid;
        if(xiao<1)xiao=1;
        if(check(xiao,da,k))r=mid;
        else l=mid;
    }
//  check(5,155,1096);
    if(flag)printf("%lld\n",r);
    else printf("-1\n");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值