做的中等题,难题总结(2)

jzoj2865. 【集训队互测 2012】Attack(中等题)

虽然标算没有使用暴力,但是这道题的暴力算法还是值得记录一下。

我这种不会整体二分的蒟蒻肯定使用暴力算法。

首先我们可以根据题意得到一个$O(nmlog_2n)$的做法,显然会超时。可以用${nth\_element}$优化掉一个log。但是还是会tle(吸臭氧都不行)

这道题可以把所有点按照权值排序,设$id[i]$表示第i个节点现在在数组的哪一个位置。然后从小到大枚举权值,加入一个表的末尾。最后输出第k个即可。

实际上。我们把结点放进表末尾的顺序是按照权值从小到大。这样子就可以保证表是有序的。

这题还有修改操作。但是不难。直接修改对应位置即可

#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize("O3")
#define N 60010
int n,m,ar[N],po[N],b[N];
struct no{
    int x,y,z,id;
    bool operator <(const no &rhs)const{
        return z<rhs.z;
    }
}o[N];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
        scanf("%d%d%d",&o[i].x,&o[i].y,&o[i].z),o[i].id=i;
    sort(o,o+n);
    for(int i=0;i<n;i++)
        b[o[i].id]=i;
    while(m--){
        char s[10];
        scanf("%s",s);
        if(s[0]=='S'){
            int c,d;
            scanf("%d%d",&c,&d);
            swap(o[b[c]].x,o[b[d]].x);
            swap(o[b[c]].y,o[b[d]].y);
            swap(o[b[c]].id,o[b[d]].id);
            swap(b[c],b[d]);
        }
        else{
            int a,b,c,d,k,ta,tb,tc,td;
            scanf("%d%d%d%d%d",&ta,&tb,&tc,&td,&k);
            a=min(ta,tc);c=max(ta,tc);
            b=min(tb,td);d=max(tb,td);
            int ct=0;
            for(int i=0;i<n;i++)
                if(o[i].x<=c&&o[i].x>=a&&o[i].y<=d&&o[i].y>=b)
                    ar[++ct]=o[i].z;
            if(ct<k)printf("It doesn't exist.\n");
            else printf("%d\n",ar[k]);
        }
    }
}
View Code

 

jzoj2867. 【集训队互测 2012】Contra (中等题)

可以使用dfs求状态,但是原来的dfs求出来的状态集,在更新最终答案的时候会延后一个单位所以不可以使用dfs。

先贴代码

#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize(3)
int n,r,q,ct,nt[105][2],nm[105][105];
struct nn{
    int x,y;
    bool operator <(const nn &rhs)const{
        return x<rhs.x||(x==rhs.x&&y<rhs.y);
    }
}a[105];
double s;
map<nn,int>ma;
struct no{
    double a[105][105];
}bz,x;
no mul(no x,no y){
    no z;
    memset(z.a,0,sizeof(z.a)); 
    for(int i=0;i<=ct;i++)
        for(int j=0;j<=ct;j++)
            for(int k=0;k<=ct;k++)
                if(x.a[i][k]>1e-15&&y.a[k][j]>1e-15)z.a[i][j]+=x.a[i][k]*y.a[k][j];
    return z;
}
double mul(double p,int y){
    memset(bz.a,0,sizeof(bz.a));
    memset(x.a,0,sizeof(x.a));
    for(int i=0;i<=100;i++)
        bz.a[i][i]=1;
    ct=0;
    for(int j=0;j<=r;j++)
        for(int i=min(j+1,q);i<=q;i++)    
            nm[i][j]=ct++;
    for(int j=0;j<=r;j++)
        for(int i=min(j+1,q);i<=q;i++){
            x.a[nm[i][j]][ct]+=p*min(j+1,r);
            x.a[nm[i][j]][nm[min(i+1,q)][min(j+1,r)]]+=p;
            if(i>1)x.a[nm[i][j]][nm[i-1][0]]+=(1-p);
        }
    x.a[ct][ct]=1;
    while(y){
        if(y&1)bz=mul(bz,x);
        x=mul(x,x);
        y>>=1;
    }
    return bz.a[nm[q][0]][ct];
}
int main(){
    scanf("%d%d%d%lf",&n,&r,&q,&s);
    double a=0,b=1,ans=-2;
    while(a+1e-9<b){
        double md=(a+b)*0.5;
        if(mul(md,n)>s)b=md-1e-9,ans=md;
        else a=md+1e-9;
    }
    if(ans!=-2)printf("%.6lf",ans);
    else printf("Impossible.");
}//2 1 2 1
View Code

 jzoj6011. 【NOIP2019模拟1.25A组】天天爱跑步 (难题)

注意到走的过程很像更相减损术,gcd值不变。所以可以把题目与gcd联系起来。

又注意到对于一个点$(x,y)$,只有1种方法使其变小。但是有2种方法让它变大。于是可以把这道题和树联系起来。

实际上,我们可以把$(x,y)->(x,x+y)$看作向右儿子移动,$(x,y)->(x+y,y)$看作向左儿子移动。则问题就转换成树上问题:有一个无限大的二叉树。每次移动产生1代价,给出若干个起点和终点。每个起点只能移动到一个终点。询问最小代价。我们可以在$log(n)$的时间内求出每一个点的深度。

由于二叉树太大。不可以直接建。于是可以考虑建一个虚树,把点放上去。然而建虚树的过程也太慢。要对节点排序,消耗巨量的时间。即使使用了$O(log_2 树高)$求lca,也会tle成70分。

定义这颗树上的“链的跳动”为:一个点向上跳,跳过的全是父亲的左儿子/右儿子边。则视为在链上跳动。一个点向上跳,跳到第一个$(x,y)$产生变迁(大小关系发生改变)的地方$(a,b)$,则视为跳到链顶。

考虑如下一种建树方法。可以把每个点向链顶连边。然后dfs整棵树计算答案。但是这种方法不能正确统计出答案。因为在新树上的lca不等于原树上的lca,原树的关系不可以维持

实际上,我们可以把每个点的子节点(一定在同一条链上)按照深度从小到大排序。然后深度小的累加深度大的答案即可。

最后就是统计答案的问题了。我们可以把起点的权值设为1,终点设为-1,把子树的1和-1尽量配对,剩下来的1向上合并就好了。

#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#define O3 __attribute__((optimize("-O3")))
#define N 4000010
#define mo 4000007
typedef long long ll;
struct no{
    ll x,y;
    bool operator ==(const no &rhs)const{
        return (x==rhs.x&&y==rhs.y);
    }
}a[N],hs[N];
int operator !=(no x,no y){return !(x==y);}
int hh(no v){return (v.x%mo*200407296+v.y%mo*998244353)%mo;}
vector<int>vc[N][2];
int n;ll bz,ans,dep[N],sz[N];
O3 no is(no x){
    int va=hh(x),bz=1;
    while(hs[va].x&&hs[va].y&&x!=hs[va])va=(va+1)%mo;
    if(!(hs[va].x||hs[va].y))hs[va]=x,dep[va]=x.x+x.y,bz=0;
    return (no){bz,va};
}
O3 int cmp(int x,int y){return dep[x]>dep[y];}
O3 void dfs(int x){
    ll ct=0;
    for(int i=0;i<2;i++)
        if(vc[x][i].size()){
            for(int j=0;j<vc[x][i].size();j++)
                dfs(vc[x][i][j]);
            sort(vc[x][i].begin(),vc[x][i].end(),cmp);
            int ls=vc[x][i][0];
            ll vv=sz[ls],bz;
            if(i)bz=hs[x].x;else bz=hs[x].y;
            for(int j=1;j<vc[x][i].size();j++){
                ans+=abs(vv)*((dep[ls]-dep[vc[x][i][j]])/bz);
                vv+=sz[vc[x][i][j]];
                ls=vc[x][i][j];
            }
            ct+=vv;ans+=abs(vv)*((dep[ls]-dep[x])/bz);
        }
    sz[x]+=ct;
}
O3 int main(){
    scanf("%d",&n);
    for(int i=1;i<=n*2;i++){
        scanf("%lld%lld",&a[i].x,&a[i].y);
        bz=__gcd(a[i].x,a[i].y);
        a[i].x/=bz;a[i].y/=bz;
        ll x=a[i].x,y=a[i].y,tp;
        if(is(a[i]).x)continue;
        while(x!=y){
            no on=(no){x,y},nn;
            if(x>y)x%=y,tp=0;
            else y%=x,tp=1;
            if(!x||!y)x=y=1;
            nn=(no){x,y};
            no xx=is(on),yy=is(nn);
            vc[yy.y][tp].push_back(xx.y);
            if(yy.x)break;
        }
    }
    for(int i=1;i<=n;i++){
        sz[is(a[i]).y]++;
        sz[is(a[i+n]).y]--;
    }
    dfs(is((no){1,1}).y);
    printf("%lld",ans);
}
View Code

 

jzoj3400. 【GDOI2014模拟】旅行

 

jzoj3738. 【NOI2014模拟7.11】理想城市(city)  

 

jzoj6293 迷宫(中等题)

直接动态dp即可。注意常数

#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize("O2")
#define mmin(x,y) x<y?x:y
int n,m,q,v[10][200010],op,a,b,c,d,tx[4]={-1,0,1},ty[4]={0,1,0},di[10][200010],ok,gc;
struct no{
    int a[6][6];
}st[1000010],e[200010],bz,g;
no mul(no x,no y){
    no z;
    memset(z.a,63,sizeof(z.a));
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)if(x.a[i][j]<1e9)
            for(int k=0;k<n;k++)if(y.a[j][k]<1e9)
                z.a[i][k]=mmin(z.a[i][k],x.a[i][j]+y.a[j][k]);
    return z;
}
struct nn{
    int x,y;
};
void mod(int o,int l,int r,int x){
    if(l==r){st[o]=e[l];return;}
    int md=(l+r)/2;
    if(x<=md)mod(o*2,l,md,x);
    else mod(o*2+1,md+1,r,x);
    st[o]=mul(st[o*2],st[o*2+1]);
}
void qu(int o,int l,int r,int x,int y){
    if(r<x||y<l)return;
    if(x<=l&&r<=y){
        if(!ok)ok=1,g=st[o];
        else g=mul(g,st[o]);
        return;
    }
    int md=(l+r)/2;
    qu(o*2,l,md,x,y);qu(o*2+1,md+1,r,x,y);
}
void bd(int o,int l,int r){
    if(l==r){
        st[o]=e[l];
        return;
    }
    int md=(l+r)/2;
    bd(o*2,l,md);bd(o*2+1,md+1,r);
    st[o]=mul(st[o*2],st[o*2+1]);
}
void get(int x){
    queue<nn>q;
    for(int i=0;i<n;i++){
        if(v[i][x])q.push((nn){i,x});
        for(int j=x;j<x+2;j++)
            for(int k=0;k<n;k++)
                di[k][j]=1e9;
        di[i][x]=0;
        while(!q.empty()){
            nn x=q.front();q.pop();
            for(int i=0;i<3;i++){
                int nx=x.x+tx[i],ny=x.y+ty[i];
                if(nx<0||nx>=n||ny<0||ny>=m)continue;
                if(di[nx][ny]>di[x.x][x.y]+1&&v[nx][ny]){
                    di[nx][ny]=di[x.x][x.y]+1;
                    q.push((nn){nx,ny});
                }
            }
        }
        for(int j=0;j<n;j++)
            e[x].a[i][j]=di[j][x+1];
    }
    if(gc)mod(1,0,m-2,x);
}
int main(){
    //freopen("maze.in","r",stdin);
    //freopen("maze.out","w",stdout);
    scanf("%d%d%d",&n,&m,&q);
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            scanf("%d",&v[i][j]);
    for(int i=0;i<n;i++)bz.a[i][i]=1;
    for(int i=0;i<m;i++)get(i);
    bd(1,0,m-2);
    gc=1;
    while(q--){
        scanf("%d",&op);
        if(op==1){
            scanf("%d%d",&a,&b);
            a--;b--;v[a][b]^=1;
            get(b);if(b>0)get(b-1);
        }
        else{
            scanf("%d%d%d%d",&a,&b,&c,&d);
            a--;b--;c--;d--;
            if(b>d)printf("-1\n");
            else if(b==d){
                if(a>c)swap(a,c);
                int ok=1;
                for(int i=a;i<=c;i++)
                    if(!v[i][b])ok=0;
                if(ok)printf("%d\n",c-a);
                else printf("-1\n");
            }
            else{
                ok=0;
                qu(1,0,m-2,b,d-1);
                if(g.a[a][c]<1e9)printf("%d\n",g.a[a][c]);
                else printf("-1\n");
            }
        }
    }
}
View Code

 

转载于:https://www.cnblogs.com/rilisoft/p/11288757.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值