UOJ#123. 【NOI2013】小Q的修炼

12 篇文章 0 订阅
1 篇文章 0 订阅

第一次完整做完一道题答….
这道题答似乎算是十分友好的

前面几个点的代码没存,只有最后几个点的代码(不过后来看了一下感觉这个代码是能跑所有点的)

case1,2

写个暴力遍历所有情况,case2要跑一会

case3

我们看一下这个train3.in
发现他分成了很多块,每个块的大小是170,在每个块内他会对变量2~12修改,在块的末尾,他会让1加上这些变量,然后把除了2的变量清空(变量2在所有块中只改了1次,其他操作也均不涉及他所以我们可以忽略2),然后跳到下个块
因此不同块之间是互不影响的,我们可以对每个块内爆搜,再把这些块拼起来输出

case4,5,6

变量只有2个,且没有涉及变量1的判断,询问,且变量2只有在一开始是加的,后面全是减的
再观察一下数据发现,把2初始加的值视为资金,每个块内相当与花钱买成就(变量1),你买不起时可以选择跳过,你买得起时也可以选择跳过,且所有操作都只会往后面的操作跳
于是可以做个dp,f[i][j]表示dp到第i个操作,还未进行第i个操作,剩余资金j的最大成就,输出方案就记录一个 p[i][j] p [ i ] [ j ] 表示 f[i][j] f [ i ] [ j ] 这个状态是从哪里转移过来的

case7,8,9,10

变量2仍然只在开头加了一次
发现数据仍然分成了若干块,每个块内变量2只会减1次,然后对3~12做一些修改,在块的末尾把这些变量加到成就上然后清零
每个块只会往后面的块跳,但不一定是连着的下一个块
和上面类似的,在每个块内爆搜,可以处理出这个块内相当于你可以选择花费一些资金买一些成就,不管是否买不买得起你都可以选择跳到后面的某个块内
把上面的块内爆搜和dp结合起来
f[i][j] f [ i ] [ j ] 表示dp到第i个块,还未进行第i个块的操作,剩余资金j,的最大成就,方案同样记录一个 p[i][j] p [ i ] [ j ] ,把最优解经过的若干个块拼起来后再把块内的路径展开接在一起

具体有些细节不好描述(你们写完跑不出来或者跑出错的调一下就知道了2333)

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define pb push_back
#define inf 1e9
using namespace std;

inline int read()
{
    int x,f=1; char c;
    while(!((c=getchar())>='0'&&c<='9')) if(c=='-') f=-1;
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
    return x*f;
}
inline void up(int &a,const int &b){if(a<b)a=b;}
const int maxn = 36000;
const int maxc = 1005;

int n,m;
struct data{int t,x;};
struct node
{
    int type,sig;
    data x,y;
    int to[2];
}op[maxn];

char str[110];
void Input()
{
    for(int i=1;i<=n;i++)
    {
        scanf("%s",str);
        if(str[0]=='v')
        {
            op[i].type=1;
            op[i].x=(data){1,read()};
            scanf("%s",str); op[i].sig=str[0]=='+'?1:-1;
            scanf("%s",str); op[i].y.t=str[0]=='v',op[i].y.x=read();
        }
        else if(str[0]=='s')
        {
            op[i].type=2;
            op[i].to[0]=read(),op[i].to[1]=read();
        }
        else
        {
            op[i].type=3;
            scanf("%s",str); op[i].x.t=str[0]=='v'; op[i].x.x=read();
            scanf("%s",str); op[i].y.t=str[0]=='v'; op[i].y.x=read();
            op[i].to[0]=read(),op[i].to[1]=read();
        }

        if(op[i].to[0]<1||op[i].to[0]>n) op[i].to[0]=n+1;
        if(op[i].to[1]<1||op[i].to[1]>n) op[i].to[1]=n+1;
    }
}

struct Block
{
    int l,r;
    int vy[2],vd[2],vc[2],ful;
    vector<int>ansi;
}b[maxn]; int bn;
int bel[maxn];

int ans;
int now[20];
int t[maxn],tp;
int nowb;

void dfs(const int i)
{
    if(i<b[nowb].l||i>b[nowb].r)
    {
        if(ans<now[1])
        {
            b[nowb].vy[1]=i,b[nowb].vd[1]=now[2]-op[1].y.x;
            ans=now[1];
            b[nowb].ansi.clear();
            for(int i=1;i<=tp;i++) b[nowb].ansi.pb(t[i]);
        }
        return;
    }

    if(op[i].type==1)
    {
        int tmp=op[i].y.t?now[op[i].y.x]:op[i].y.x;
        now[op[i].x.x]+=tmp*op[i].sig;

        dfs(i+1);

        now[op[i].x.x]-=tmp*op[i].sig;
    }
    else if(op[i].type==2)
    {
        int tc=0;
        t[++tp]=tc,dfs(op[i].to[tc]),tp--;
        t[++tp]=!tc,dfs(op[i].to[!tc]),tp--;
    }
    else
    {
        int x=op[i].x.t?now[op[i].x.x]:op[i].x.x,y=op[i].y.t?now[op[i].y.x]:op[i].y.x;
        if(x<y) dfs(op[i].to[0]);
        else dfs(op[i].to[1]);
    }
}

int f[maxn][maxc],p[maxn][maxc],pc[maxn][maxc];
void dp()
{
    for(int i=1;i<=bn;i++) for(int j=0;j<maxc;j++) f[i][j]=-inf;
    f[1][op[1].y.x]=0;

    for(int i=1;i<bn;i++) for(int j=0;j<maxc;j++) if(f[i][j]!=-inf)
    {
        if(j+b[i].vd[0]>=0)
        {
            int y=b[i].vy[0],nj=j+b[i].vd[0];
            if(f[bel[y]][nj]<f[i][j]+b[i].vc[0]) f[bel[y]][nj]=f[i][j]+b[i].vc[0],p[bel[y]][nj]=i,pc[bel[y]][nj]=0;
        }
        if(j+b[i].vd[1]>=0)
        {
            int y=b[i].vy[1],nj=j+b[i].vd[1];
            if(f[bel[y]][nj]<f[i][j]+b[i].vc[1]) f[bel[y]][nj]=f[i][j]+b[i].vc[1],p[bel[y]][nj]=i,pc[bel[y]][nj]=1;
        }
    }
}


int main()
{
    freopen("train8.in","r",stdin);
    freopen("train8.out","w",stdout);

    scanf("%d%d",&n,&m);

    srand(1000007);

    Input();

    int ssum=0;
    b[bn=1].l=2;
    for(int i=2;i<=n;i++)
    {
        if(op[i].type==1&&op[i].x.x==12&&op[i].y.t&&op[i].y.x==12&&op[i].sig==-1)
        {
            b[bn].r=i; b[bn].ful=0;
            for(int j=b[bn].l;j<=b[bn].r;j++) 
            {
                bel[j]=bn;
                if(op[j].type==2&&!b[bn].ful)
                {
                    b[bn].ful=1;
                    b[bn].vy[0]=op[j].to[1],b[bn].vd[0]=0,b[bn].vc[0]=0;
                }
            }

            ans=-inf,nowb=bn; now[2]=op[1].y.x; dfs(b[bn].l);
            b[bn].vc[1]=ans;
            ssum-=b[bn].vd[1];

            b[++bn].l=i+1;
        }
    }
    bel[n+1]=bn; b[bn].r=n+1;
    for(int i=b[bn].l;i<=b[bn].r;i++) bel[i]=bn;

    dp();

    int x=bn,y=0;
    for(int i=1;i<maxc;i++) if(f[x][i]>f[x][y]) y=i;
    tp=0;
    while(x!=1)
    {
        int i=p[x][y];
        if(pc[x][y]==0)
        {
            if(y+b[i].vd[1]>=0) t[++tp]=1;
            y-=b[i].vd[0];
        }
        else
        {
            for(int j=(int)b[i].ansi.size()-1;j>=0;j--) t[++tp]=b[i].ansi[j];
            y-=b[i].vd[1];
        }
        x=i;
    }
    for(int i=tp;i>=1;i--) printf("%d\n",t[i]+1);
    //for(int i=1;i<=ansn;i++) printf("%d\n",ansi[i]+1);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值