vijos + Bzoj划水记(二)

Prog1.
ZJOI2014 力
背(吐)景(槽):
这题我真的是醉了……
不懂小学数学简直是不能够啊……
题意:

Fj=i<jqiqj(ij)2i>jqiqj(ij)2

又有:
Ei=Fi/qi

求n个数的 Ei
题解:
Ej=Fj/qj=(i<jqiqj(ij)2i>jqiqj(ij)2)/qj
所以说……
Ej=i=0j1qi(ij)2i=j1n1qi(ij)2

当时化简到这一步我一点反应都没有。
我就是OI界的智障TAT
f[i]=qi , g[ji]=1(ij)2
原式可化简为:
Ej=i=0j1f[i]g[ji]i=j1n1f[i]g[ji]

如果这都看不出来是卷积的话我就可以去死了……
然而好像……
j - i会出负数啊怎么办呢?
Ej=i=0j1f[i]g[ji]i=j1n1f[i]g[ji+n]

FFT。
预处理一下g[],然后就没有了。
代码十分钟写完了。
调了30分钟。
死因:

for(int i = 1;i < n;i ++)g[i].r = 1 / i / i;

妈妈我以后所有的double计算都会加.0的TAT

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define Rep(i,n) for(int i = 1;i <= n;i ++)
#define RepG(i,x) for(int i = head[x];~ i;i = edge[i].next)
#define RD(i,x,n) for(int i = x;i <= n;i ++)
#define Rep_0(i,n) for(int i = 0;i < n;i ++)
#define Rep0n(i,n) for(int i = 0;i <= n;i ++)
#define PI M_PI
using namespace std;
struct Virt 
{
    double r,i;
    Virt (double r = 0.0,double i = 0.0)
    {
        this -> r = r;
        this -> i = i;
    }
    Virt operator+(const Virt &x)
    {
        return Virt(r + x.r,i + x.i);
    }
    Virt operator-(const Virt &x)
    {
        return Virt(r - x.r,i - x.i);
    }
    Virt operator*(const Virt &x)
    {
        return Virt(r * x.r - i * x.i,x.r * i + r * x.i);
    }
};
const int MAXN = 262148;
int n,m,LG,Rev[MAXN],N;
void Rader()
{
    m = (n - 1) << 1;
    for(N = 1;N <= m;LG ++,N <<= 1);
    for(int i = 1;i <= N;i ++)
        Rev[i] = ((Rev[i >> 1] >> 1) | (i & 1) << (LG - 1));
}
/*void Rader()
{
    for(n = 1;n <= m;n <<= 1,LG ++);
    for(int i = 1;i < n;i ++)
        Rev[i] = (Rev[i >> 1] >> 1) | ((i & 1) << (LG - 1));
}*/
Virt q[MAXN],ans[MAXN],g[MAXN],gr[MAXN];
void FFT(Virt *F,int ty = 1)
{
    for(int i = 0;i < N;i ++)if(i < Rev[i])swap(F[i],F[Rev[i]]);
    for(int i = 1;i < N;i <<= 1)
    {
        Virt wn(cos(PI / i),ty * sin(PI / i));
        for(int j = 0;j < N;j += (i << 1))
        {
            Virt w(1,0);
            for(int k = 0;k < i;k ++,w = w * wn)
            {
                Virt u = F[j + k],v = F[j + k + i] * w;
                F[j + k] = u + v;
                F[j + k + i] = u - v;
            }
        }
    }
    if(ty == -1)Rep_0(i,N)F[i].r /= N;
}
int main ()
{
    scanf("%d",&n);
    Rep_0(i,n)scanf("%lf",&q[i].r);
    Rep(i,n - 1)g[i].r = 1.0 / i / i;
    Rep_0(i,n)gr[i].r = g[n - i - 1].r;
    Rader();
    FFT(q);FFT(g);
    Rep_0(i,N)g[i] = g[i] * q[i];
    FFT(g,-1);
    FFT(gr);
    Rep_0(i,N)gr[i] = q[i] * gr[i];
    FFT(gr,-1);
    Rep_0(i,n)
        ans[i] = g[i] - gr[n + i - 1];
    Rep_0(i,n)
        printf("%.8f\n",ans[i].r);
    return 0;
}

Prog2.
P1836HYS与七夕节大作战
题意:
整数价值,正实数代价的01背包。
题解:
F[n]表示装到价值为n,代价最小为多少。
跟自己的所拥有的背包容量进行比较即可。
Prog3.
P1571笨笨的导弹攻击
求一个奇怪的子序列,它满足在奇数下标的时候递增,偶数下标的时候递减。
题解:DP。

我要是再做这么水的题我自己都瞧不起自己……

Prog4.
bzoj 2654 Tree
  给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
  题目保证有解。
  数据规模和约定
  0:V<=10
  1,2,3:V<=15
  0,..,19:V<=50000,E<=100000
  所有数据边权为[1,100]中的正整数。
吐槽:
考虑到边权非常小,那我们还是给白色边加一个比较大的值好啦。
嗯……
加多少呢?
算啦算啦我觉得好不靠谱啊!
呃……能不能二分呢?
好像也不太靠谱啊!
毕竟二分复杂度是 O(nlog22n) 的,十万好像过不了啊!
怎么做呢……?
题解:
注意到边权非常小,直接把白色边加上某个权值,二分这个权值求最小生成树即可。
内心os:什么情况?
呃所以我想的就是正解?
//脑袋被门夹了……
我先更新到这里……
一下午没做几道题……

你可能感兴趣的:(vijos + Bzoj划水记(二))