旷野大计算

image

image

这垃圾语言连个不扣分的乘法都没有...

image

任务怎么这么鬼畜啊...一个一个点来

第一个点

-2a-2b?-((a+b)*2)即可。

I
I
+ 1 2
+ 3 3
- 4
O 5

第二个点

这不就是S(-17a)吗...

S(-(a+(a<<4))即可。

I
< 1 4
+ 1 2
- 3
S 4
O 5

现在我们有一些操作...是不是感觉手输这些奇怪的指令很不顺手呢

于是我们就写一个C++代码辅助生成一下...

int cnt=0;
#define op(s) (cout<<s<<"\n", ++cnt);
int input() {return op("I");}
int mul2(int p,int cm=1)
{return op("< "<<p<<" "<<cm);}
int div2(int p,int cm=1)
{return op("> "<<p<<" "<<cm);}
int cpy(int p)
{return op("C "<<p<<" 0");}
int add(int a,int b)
{return op("+ "<<a<<" "<<b);}
int fu(int a)
{return op("- "<<a);}
int addv(int a,int v)
{return op("C "<<a<<" "<<v);}
int gs(int a)
{return op("S "<<a);}
int jian(int a,int b)
{
    int t=fu(b);
    return add(a,t);
}
int out(int x)
{return op("O "<<x);}

恩所有的不扣分操作都在这了...就这么多

第三个点

计算sgn(a):

image

奥妙重重啊

稍加考虑,我们可以发现...不用S是做不了的...

那我们考虑用S怎么做。

注意到S在inf时趋近于1,在-inf时趋近于0,在0时趋近于0.5。

只要将a乘上2^2333带入S函数,然后乘2减一即可

out(addv(mul2(gs(mul2(input(),2333))),-1));

就一行 /滑稽

注意到这玩意儿已经可以替代扣分的比较结点啦~

我们定义两个函数吧...

int sgn(int x)
{return addv(mul2(gs(mul2(x,2333))),-1);}
int gp(int x)
{return gs(mul2(x,2333));}

第二个函数p会返回平移前的结果0/0.5/1。

第四个点

计算|x|。

这...我们看看扣分操作...

比较、max和乘法...

sgn(x)*x?要用乘法

max(x,-x)?要用max

这就很尴尬了...看来还是要从这个奇怪的S入手?

我们考虑导数!

当x趋近于0时,$\frac{s(x)-s(0)}{x}=s'(0)=\frac{1}{4}$

一棵赛艇!

这样当|x|充分小时s(x)就≈1/4x+0.5啦。

那我们考虑p(x)(定义在上面第三个点)这个东西当x<0时会返回0...

那么我们就直接带入s(x>>150+p(x)<<2333),这样x>=0时应该s里面会趋近于inf,所以就会变成1,否则就会≈0.5+x>>152。(注意1/4)

那么我们把这玩意儿取负,加上0.5,左移153位,对于x<0显然会变成-2x。x+(-2x)=-x。对于x>=0,带入会变成-0.5<<153,加上这个数就行啦!

啥,怎么加?加上(p(x)/2)<<153=p(x)<<152即可。

咦?你说x=0?x+=1e-30即可。

咦...p(x)<<152...那上面p(x)<<2333我就改成p(x)<<152吧...还可以顺便卡卡常数... 还是再定义一个函数~

int abs(int r)
{
    cout.setf(ios::fixed);
    cout.precision(30);
    int x=addv(r,1e-30);
    int p=gp(x);
    int py=mul2(p,152);
    int s=gs(add(div2(x,150),py));
    int bf=addv(fu(s),0.5);
    int m=mul2(bf,153);
    int ans=add(add(x,m),py);
    return ans;
}

第五个点

进制转换?模拟即可~强行送分

int main()
{
    int s=input();
    for(int i=2;i<=32;i++)
    {
        s=mul2(s);
        s=add(s,input());
    }
    out(s);
}

第六个点

又是进制转换,把十进制转回二进制?

image

好主意!

int main()
{
    cout.setf(ios::fixed);
    cout.precision(30);
    int s=addv(input(),1e-30);
    int zero=div2(s,2333);
    int fone=addv(zero,-1);
    for(int i=31;i>=0;i--)
    {
        int t=mul2(fone,i);
        int b=gp(add(s,t));
        s=add(s,mul2(fu(b),i));
        out(b);
    }
}

然而只有8分?或许可以卡卡常?

前两个点先拿个函数存起来好了...

typedef vector<int> vi;
vi cv(int s)
{
    cout.setf(ios::fixed);
    cout.precision(30);
    addv(s,1e-30);
    int zero=div2(s,2333);
    int fone=addv(zero,-1);
    vi ans; ans.resize(32);
    for(int i=31;i>=0;i--)
    {
        int t=mul2(fone,i);
        int b=gp(add(s,t));
        s=add(s,mul2(fu(b),i));
        ans[i]=b;
    }
    return ans;
}
int cv(vi x)
{
    int s=x[0];
    for(int i=1;i<32;i++)
    {
        s=mul2(s);
        s=add(s,x[i]);
    }
    return s;
}

第七个点

计算异或?

那我们只要算00、01、10、11的异或值就行了。

我构不出来...但是出题人构出来了...

image

int xor01(int a,int b)
{
    int s=add(a,b);
    int tm=mul2(fu(gp(addv(s,-1.5))));
    return add(tm,s);
}
int main()
{
    freopen("nodes7.out","w",stdout);
    cout.setf(ios::fixed);
    cout.precision(30);
    int a=input(),b=input();
    vi va=cv(a),vb=cv(b);
    vi ans; ans.resize(32);
    for(int i=0;i<32;i++) ans[i]=xor01(va[i],vb[i]);
    out(cv(ans));
}

还是8分...算了就这样先弃疗好了。

第八个点

计算a/10?

我们可以对1/10进行二进制分解...

这时候第二题的高精度库就可以派上用场了233

用高精度打个表:

Decimal s=1,cur=0,tar=0.1;
int main()
{
    for(int i=1;i<=300;i++)
    {
        s/=2;
        if(cur+s<=tar) cur+=s, cout<<i<<",";
    }
}

然后就可以直接肛了

int list[]={4,5,8,9,12,13,16,17,20,21,24,25,28,29,32,33,36,37,40,41,44,45,48,49,52,53,56,57,60,61,64,65,68,69,72,73,76,77,80,81,84,85,88,89,92,93,96,97,100,101,104,105,108,109,112,113,116,117,120,121,124,125,128,129,132,133,136,137,140,141,144,145,148,149,152,153,156,157,160,161,164,165,168,169,172,173,176,177,180,181,184,185,188,189,192,193,196,197,200,201,204,205,208,209,212,213,216,217,220,221,224,225,228,229,232,233,236,237,240,241,244,245,248,249,252,253,256,257,260,261,264,265,268,269,272,273,276,277,280,281,284,285,288,289,292,293,296,297,300};
int ln=31;
int d10(int x)
{
    int tmp[233];
    for(int i=0;i<ln;i++) tmp[i]=div2(x,list[i]);
    int cur=tmp[0];
    for(int i=1;i<ln;i++) cur=add(cur,tmp[i]);
    return cur;
}

那个ln参数是人工调出来的...

并没有看懂这个点的题解啊QAQ

第九个点

排序?我们写一个冒泡排序!

接下来我们考虑如何求出min(a,b)...

其实只要a+min(b-a,0)即可!

那么我们就可以这样求出a和b两个数的较小值,从而将a和b放好位置(因为和不变)

所以我们写一个冒泡排序就可以了。min0参见第四个点。

int min0(int r)
{
    cout.setf(ios::fixed);
    cout.precision(30);
    int x=addv(r,1e-30);
    int p=gp(x);
    int py=mul2(p,151);
    int s=gs(add(div2(x,150),py));
    int bf=addv(fu(s),0.5);
    int m=mul2(bf,152);
    return fu(add(m,py));
}
int aid[23];
void relax(int a,int b)
{
    int s=add(aid[a],aid[b]);
    aid[a]=add(aid[a],min0(add(fu(aid[a]),aid[b])));
    aid[b]=add(s,fu(aid[a]));
}
int main()
{
    freopen("nodes9.out","w",stdout);
    for(int i=1;i<=16;i++) aid[i]=input();
    for(int i=1;i<=16;i++)
    {
        for(int j=i+1;j<=16;j++) relax(i,j);
    }
    for(int i=1;i<=16;i++) out(aid[i]);
}

最后一个点太难写啦!看心情可能会再更

成功得到85分~

转载于:https://www.cnblogs.com/zzqsblog/p/5715551.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值