NOIP提高组模拟赛24


差点又因为文件暴0。。。

A. matrix

状压,\(f[i][j][k]\)表示第\(i-1\)行状态为\(j\),第\(i\)行状态为\(k\)的最小花费。

貌似复杂度不对?但是舍弃非法状态后复杂度是可以接受的,具体怎么证明我不会

code
#include
#include

using namespace std;
int min(int x,int y){return x>1))&ms);
                    f[i][ns][mp[i+1]|op]=min(v[i][op]+f[i-1][j][k],f[i][ns][mp[i+1]|op]); 
                    // printf("%d %d %d + %d -> %d %d %d == %d\n",i-1,j,k,v[i][op],i,ns,mp[i+1]|op,f[i][ns][mp[i+1]|op]);
                }       
            }
        }
    }
    int ans=inf;
    for(int i=0;i<=ms;++i)ans=min(ans,f[n][ms][i]);
    printf("%d\n",ans);

    return 0;
}

B. block

第一问按照\(1->val 2->key\)排序,从大到小考虑每个数有多少位置可以放,统计一下即可。

可恶,第二关键字搞错了,然而.....

第二问直接拿链表暴力搞有\(90\)

正解平衡树二分或者奇妙线段树

平衡树二分我不理解,感觉那玩意两个关键字,没有二分所需要的单调性。。

线段树就是,你取一个数,所有比他小的数的\(key\)需要\(--\),然后每次贪心选择字典序最小的,但是需要保证\(key>0\),也就是说如果有\(key==1\)的需要优于字典序考虑

注意上面那个变化的\(key\)是一个类似备份的东西,它可以变,但是比较字典序需要用原数

然后,线段树有点细节啊。。。

code
#include
#include
#include

using namespace std;

const int mod=1e9+7;
const int maxn=500005;
struct node{
    int key,val;
}d[maxn];
int n;
bool cmp(node x,node y){
    if(x.val!=y.val)return x.val>y.val;
    return x.keyR)return;
        if(L<=l&&r<=R){
            t[x].val+=v;
            t[x].tag+=v;
            return;
        }
        int mid=(l+r)>>1;
        if(t[x].tag)push_down(x);
        if(L<=mid)modify(x<<1,l,mid,L,R,v);
        if(R>mid)modify(x<<1|1,mid+1,r,L,R,v);
        push_up(x);
    }
    void modify(int x,int l,int r,int pos,int v){
        if(l==r){
            t[x].pos=t[x].vpos=l;
            t[x].val=t[x].tu=v;
            return;
        }
        int mid=(l+r)>>1;
        if(t[x].tag)push_down(x);
        if(pos<=mid)modify(x<<1,l,mid,pos,v);
        else modify(x<<1|1,mid+1,r,pos,v);
        push_up(x);
    }

}T;

int main(){
    freopen("block.in","r",stdin);
    freopen("block.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d%d",&d[i].key,&d[i].val);
    work();
    sort(d+1,d+n+1,cmp2);
    for(int i=1;i<=n;++i)T.modify(1,1,n,i,d[i].key);
    for(int i=1;i<=n;++i){
        int pos=T.t[1].val==1?T.t[1].vpos:T.t[1].pos;
        printf("%d %d\n",d[pos].key,d[pos].val);
        T.modify(1,1,n,1,pos-1,-1);
        T.modify(1,1,n,pos,498244353);
    }
    return 0;
}

C. graph

\(emmm..\)

一个教训

ceil(x/y)是假的ceil((float)x/y)才对,为啥?类型转化。。。。。。

二维最短路,\(dis[i][j]\)表示\(1->i\)走了\(j\)\(-1\)路径的最短路

枚举走几条\(-1\)为最短路,解不等式组

\(dis [n] [j] + val * j >= dis [n] [i] + val * i\)

解出来的范围随便取个数跑\(1-i\),\(n-i\)的最短路,枚举点看是否可以为最短路上的点,(\(d[0][j]+d[1][j]==val*i+dis[n][i]\)

不过\(lyin\)说这个解法假了,正解应该是维护凸包.

code
#include
#include
#include
#include
#include

using namespace std;

const int maxn=1005;
const int maxm=2005;
typedef long long ll;
int n,m,head[maxn],tot,cnt;
ll inf=0x3f3f3f3f3f3f3f3f;
bool ans[maxn];
struct edge{
    int to,net,val;
}e[maxm<<1|1];
void add(int u,int v,int w){
    e[++tot].net=head[u];
    head[u]=tot;
    e[tot].to=v;
    e[tot].val=w;
}

struct node{
    int x,cnt;
    ll val;
    node(){}
    node(int _x,int _cnt,ll _val){
        x=_x;cnt=_cnt;val=_val;
    }
    bool operator <(node x)const {
        return val>x.val;
    }
};
priority_queueq;
bool vis2[maxn][maxm];
ll dis[maxn][maxm];
void dijj(){
    memset(vis2,0,sizeof(vis2));
    memset(dis,0x3f,sizeof(dis));
    dis[1][0]=0;q.push(node(1,0,0));
    while(!q.empty()){
        node x=q.top();q.pop();
        if(vis2[x.x][x.cnt])continue;
        vis2[x.x][x.cnt]=1;
        for(int i=head[x.x];i;i=e[i].net){
            int v=e[i].to;
            if(e[i].val==-1){
                if(dis[v][x.cnt+1]>dis[x.x][x.cnt]&&x.cnt<=cnt){
                    dis[v][x.cnt+1]=dis[x.x][x.cnt];
                    q.push(node(v,x.cnt+1,dis[v][x.cnt+1]));
                }
            }else{
                if(dis[v][x.cnt]>dis[x.x][x.cnt]+e[i].val){
                    dis[v][x.cnt]=dis[x.x][x.cnt]+e[i].val;
                    q.push(node(v,x.cnt,dis[v][x.cnt]));
                }
            }
        }
    }
}

ll d[2][maxn];
bool vis [maxn];

void dij(int op,ll va){
    memset(vis,0,sizeof(vis));
    int s=op==0?1:n;
    d[op][s]=0;
    q.push(node(s,0,0));
    while(!q.empty()){
        node x=q.top();q.pop();
        if(vis[x.x])continue;
        vis[x.x]=1;
        for(int i=head[x.x];i;i=e[i].net){
            int v=e[i].to;
            ll w=e[i].val==-1?va:e[i].val;
            if(d[op][v]>d[op][x.x]+w){
                d[op][v]=d[op][x.x]+w;
                q.push(node(v,0,d[op][v]));
            }
        }
    }
}


int main(){
    freopen("graph.in","r",stdin);
    freopen("graph.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i){
        int u,v,w;scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);add(v,u,w);if(w==-1)++cnt;
    }
    dijj();
    for(int i=0;i<=cnt;++i){
        if(dis[n][i]==inf)continue;
        ll l=0,r=inf;bool flag=0;
        for(int j=0;j<=cnt;++j){
            if(i==j)continue;
            ll x=dis[n][j]-dis[n][i];
            ll y=i-j;
            // dis [n] [j] + val * j >= dis [n] [i] + val * i
            // dis [n] [j] - dis [n] [i] >= (i-j) * val
            // x >= y * val
            if(x<=0&&y>0){flag=1;break;}
            if(x>0&&y<0)continue;
            if(y<0)l=max(l,ll(ceil((float)x/y)));
            else r=min(r,ll(x/y));
        }
        if(flag||l>r)continue;
        memset(d,0x3f,sizeof(d));
        dij(1,l);dij(0,l);
        ll mxl=l*i+dis[n][i];
        for(int j=2;j