Heoi2014系列题解

Bzoj3609人人尽说江南好

显然我们要聚集起一个大小为m的石堆需要m - 1次的合并操作,我们可以把贡献单独拿出来看,我们将场上所有石子移动到无法移动的状态步数一定和把所有石子依次合并至上限的次数一样,因为。。。此处省略一千言。。 大概意会一下吧,感觉不好言传。。。大概是每次合并贡献实际是相同的这种,就像你算$x_1*x_2*x_3*...*x_n$的值一样,你没有办法通过改变乘的顺序减少乘的次数。

所以直接算出需要多少步,判一判奇偶输出答案。

代码 :

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define low(x) ((x)&(-(x)))
#define LL long long
#define eps 1e-9
using namespace std;

#define int int
inline int Max(int a,int b) {return a>b?a:b;}
inline int Min(int a,int b) {return a<b?a:b;}
inline int Abs(int a) {return a>0?a:-a;}
inline int Sqr(int a) {return a*a;}
#undef int

int T,n,m,ans;

int main() {
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d",&n,&m);
        ans=(n/m)*(m-1);ans+=Max(n%m-1,0);
        printf("%d\n",ans&1^1);
    }
    return 0;
}

Bzoj3610林中路径

如果要求的是$t$的和就直接一发矩阵快速幂就可以了,然而要求$t^2$的和。。。怎么办呢?我们可以维护多个矩阵。

设 t 为三个矩阵的集合

第一个矩阵 f 维护路径长度小于要求的路径的长度的平方和

第二个矩阵 g 维护长度小于要求的路径的个数

第三个矩阵 z 维护长度小于要求的路径的长度和

那么扩展的时候,假设t : i->j 有长为k1,k2,k3的三条路径,t‘ : j->k 有长度为k4,k5的两条路径,那么相乘的结果应该是如下的

F -> $(k1+k4)^2+(k1+k5)^2+(k2+k4)^2+...+(k3+k5)^2$ = $2*(k1^2+k2^2+k3^2)+3*(k4^2+k5^2)+2*(k1+k2+k3)*(k4+k5)$ = $g‘*f+g*f‘+2*z*z‘$

G -> $g*g‘$

Z -> $(k1+k4)+(k1+k5)+(k2+k4)+...+(k3+k5)$ = $2*(k1+k2+k3)+3*(k4+k5)$ = $g‘*z+g*z‘$

但是这样统计路径会有重复,我们发现重复是因为每条路径被分成两段有多种方案。

那么我们可以预处理出每个二的幂次长度路径的对应矩阵(路径长度一定为2的幂次而不是小于等于

那么我们就可以像数位dp一样统计

实际操作上我们对于长度为$(1011011)_2$的路径,我们去算 t[0,1000000]*t{0}+t[0,10000]*t{1000000}+t[0,1000]*t{1010000}+t[0,10]*t{1011000}+t[0,1]*t{1011010}

代码 :

//That‘s right ,I am killer .
#include<bits/stdc++.h>
#define MOD 1000000007
#define LL long long
using namespace std;

#define int int
inline int Max(int a,int b) {return a>b?a:b;}
inline int Min(int a,int b) {return a<b?a:b;}
inline int Sqr(int a) {return a*a;}
inline int Abs(int a) {return a>0?a:-a;}
#undef int

int n,m,q;LL k;

struct Matrix {
    LL x[105][105];

    void Init() {
        memset(x,0,sizeof(x));
    }

    Matrix operator + (const Matrix &b) const {
        Matrix ret;ret.Init();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                ret.x[i][j]=(x[i][j]+b.x[i][j])%MOD;
        return ret;
    }

    Matrix operator * (const Matrix &b) const {
        Matrix ret; ret.Init();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                for(int k=1;k<=n;k++)
                    ret.x[i][k]=(ret.x[i][k]+x[i][j]*b.x[j][k])%MOD;
        return ret;
    }

}e;
struct Trip{
    Matrix f,g,z;

    void Init() {
        f.Init();g.Init();z.Init();
    }

    Trip operator + (const Trip &b) const {
        Trip ret;ret.Init();
        ret.f=f+b.f;
        ret.g=g+b.g;
        ret.z=z+b.z;
        return ret;
    }

    Trip operator * (const Trip &b) const {
        Trip ret;ret.Init();
        ret.f=f*b.g+b.f*g+z*b.z+b.z*z;
        ret.g=g*b.g;
        ret.z=z*b.g+b.z*g;
        return ret;
    }

}t[33],tp[33],re,ans;

int main() {
    scanf("%d%d%lld%d",&n,&m,&k,&q);
    for(int a,b,i=1;i<=m;i++) {
        scanf("%d%d",&a,&b);
        t[0].f.x[a][b]=t[0].g.x[a][b]=t[0].z.x[a][b]=t[0].g.x[a][b]+1;
    }
    tp[0]=t[0];e.Init();
    for(int i=1;i<=n;i++) e.x[i][i]=1;
    for(int i=1;(1<<i)<=k;i++) {
        t[i]=tp[i-1]*t[i-1]+t[i-1];
        tp[i]=tp[i-1]*tp[i-1];
    }
    ans.Init();re.Init();re.g=e;
    for(int i=32;~i;i--)
        if(k>>i&1) {
            ans=ans+re*t[i];
            re=re*tp[i];
        }
    for(int s,t,i=1;i<=q;i++) {
        scanf("%d%d",&s,&t);
        printf("%lld\n",ans.f.x[s][t]);
    }
    return 0;
}

Bzoj3611大工程

问题实际上就是求树上给你一堆点,问两两之间的距离和,和距离的最值。显然可以树形dp去做,但是多组询问每次遍历全图dp可能会爆炸。这时就要请出我们的虚树了!

建完虚树dp就是了,虚树裸题。。。

有一点就是树形dp可以直接在建虚树时做完,因为建虚树的过程本身就是在dfs。

代码 :

//That‘s right ,I am killer .
#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;

#define int int
inline int Max(int a,int b) {return a>b?a:b;}
inline int Min(int a,int b) {return a<b?a:b;}
inline int Sqr(int a) {return a*a;}
inline int Abs(int a) {return a>0?a:-a;}
#undef int

#define MAXN 1000006

struct Edge{
    int next,to;
}e[MAXN*2];int head[MAXN],cnt;
inline void Insert(int a,int b) {
    e[++cnt].next=head[a];head[a]=cnt;e[cnt].to=b;
    e[++cnt].next=head[b];head[b]=cnt;e[cnt].to=a;
}

int dep[MAXN],dfn[MAXN],bln[MAXN],fa[MAXN],sz[MAXN];
inline bool cmp (const int &a,const int &b) {
    return dfn[a]<dfn[b];
}
void Dfs(int v,int d) {
    dfn[v]=++dfn[0];dep[v]=d;sz[v]++;
    for(int i=head[v];i;i=e[i].next) {
        if(!dfn[e[i].to]) {
            Dfs(e[i].to,d+1);
            sz[v]+=sz[e[i].to];
            fa[e[i].to]=v;
        }
    }
}
void HDfs(int v,int bl) {
    bln[v]=bl;int mx=0,mx_id=0;
    for(int i=head[v];i;i=e[i].next)
        if(!bln[e[i].to]&&sz[e[i].to]>mx)
            mx=sz[e[i].to],mx_id=e[i].to;
    if(mx_id) HDfs(mx_id,bl);
    for(int i=head[v];i;i=e[i].next)
        if(!bln[e[i].to]) HDfs(e[i].to,e[i].to);
}
int Lca(int u,int v) {
    while(bln[u]!=bln[v]) {
        if(dep[bln[u]]<dep[bln[v]]) swap(u,v);
        u=fa[bln[u]];
    }
    return dep[u]>dep[v] ? v:u;
}

int n,q,k,p[MAXN];
int stk[MAXN],top,mx[MAXN],mi[MAXN],mians,mxans;
LL sumans,sum[MAXN];int res[MAXN*2];

void Trans(int v,int t) {
    int len=dep[t]-dep[v];
    sumans+=len*sum[t]*(k-sum[t]);
    sum[v]+=sum[t];
    mxans=Max(mx[v]+mx[t]+len,mxans);
    mians=Min(mi[v]+mi[t]+len,mians);
    mx[v]=Max(mx[v],mx[t]+len);
    mi[v]=Min(mi[v],mi[t]+len);
    mx[t]=-INF;mi[t]=INF;sum[t]=0;
}

int main() {
    scanf("%d",&n);
    for(int a,b,i=1;i<n;i++) {
        scanf("%d%d",&a,&b);
        Insert(a,b);
    }
    Dfs(1,0);HDfs(1,1);
    scanf("%d",&q);
    for(int i=1;i<=n;i++) mi[i]=INF,mx[i]=-INF,sum[i]=0;
    for(int t=1;t<=q;t++) {
        scanf("%d",&k);
        for(int i=1;i<=k;i++) {
            scanf("%d",&p[i]);
            mx[p[i]]=0;mi[p[i]]=0;sum[p[i]]=1;
        }
        sort(p+1,p+k+1,cmp);
        top=0;mxans=0;mians=INF;sumans=0;res[0]=0;
        for(int lca,i=1;i<=k;i++) {
            lca=top ? Lca(stk[top],p[i]) : stk[top];
            res[++res[0]]=lca;res[++res[0]]=p[i];
            while(top>1&&dep[lca]<dep[stk[top-1]]) {
                Trans(stk[top-1],stk[top]);
                top--;
            }
            if(dep[lca]<dep[stk[top]]) {
                Trans(lca,stk[top--]);
                if(stk[top]!=lca) stk[++top]=lca;
            }
            stk[++top]=p[i];
        }
        while(top>1) {Trans(stk[top-1],stk[top]);top--;}
        printf("%lld %d %d\n",sumans,mians,mxans);
        mx[stk[top]]=-INF;mi[stk[top]]=INF;sum[stk[top]]=0;
    }
    return 0;
}

Bzoj3612平衡

实际上就是求一个数拆分乘1 ~ k个不同正整数且每个数大小不超过n的方案数。

设dp[n][k]为分成k个数,和为n的方案数

假设我们把所有数排成一列,这时我们把所有数都减少1

如果最小的数是1的话,那么我们就只有k-1个数和为n-k,对应dp[n-k][k-1]

否则我们就还有k个数和为n-k,对应dp[n-k][k]

所以dp[n][k]=dp[n-k][k-1]+dp[n-k][k]

不过还没完,我们分出的正整数是有上限的所以我们要从中扣除不合法状态的数量。

由于我们每一次转移相当与把所有数加1,所以不合法状态最大的数一定是lim+1

我们如果单独扣去最大的数,那么剩下数一定是合法状态且对应dp[n-(lim+1)][k-1]

所以我们最终的转移方程是dp[n][k]=dp[n-k][k-1]+dp[n-k][k]-dp[n-lim-1][k-1]

代码 :

//That‘s right ,I am killer .
#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;

#define int int
inline int Max(int a,int b) {return a>b?a:b;}
inline int Min(int a,int b) {return a<b?a:b;}
inline int Sqr(int a) {return a*a;}
inline int Abs(int a) {return a>0?a:-a;}
#undef int

int n,k,T,p,ans;
int dp[100005][15];

int main() {
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d%d",&n,&k,&p);
        int lim=n*k;ans=0;dp[0][0]=1;
        for(int i=1;i<=lim;i++) {
            for(int j=1;j<=k;j++) {
                dp[i][j]= i>=j ? dp[i-j][j]+dp[i-j][j-1]:0;
                dp[i][j]-= i>=n+1 ? dp[i-n-1][j-1]:0;
                dp[i][j]=(dp[i][j]+p)%p;
            }
        }
        for(int i=1;i<=lim;i++)
            for(int j=1;j<=k;j++)
                ans=(ans+dp[i][j]*dp[i][k-j])%p;
        k--;
        for(int i=0;i<=lim;i++)
            for(int j=0;j<=k;j++)
                ans=(ans+dp[i][j]*dp[i][k-j])%p;
        printf("%d\n",ans);
    }
    return 0;
}

Bzoj3613南园满地堆轻絮

二分答案,前面的数取到可取的最小值。然而nlogn跑5e6是不优雅的(虽然贼快

然后去看网上题解

线性做法:答案即为逆序对差值最大的一对的差值加1后除2。

正确性显然。。。。

代码 :(nlogn)

//That‘s right ,I am killer .
#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;

#define int int
inline int Max(int a,int b) {return a>b?a:b;}
inline int Min(int a,int b) {return a<b?a:b;}
inline int Sqr(int a) {return a*a;}
inline int Abs(int a) {return a>0?a:-a;}
#undef int

#define MAXN 5000006

int n,ans,sa,sb,sc,sd,a[MAXN],MOD;

LL F(int v) {
    LL ret=sd,tmp=v;
    (ret+=sc*tmp)%=MOD; (tmp*=v)%=MOD;
    (ret+=sb*tmp)%=MOD; (tmp*=v)%=MOD;
    (ret+=sa*tmp)%=MOD; return ret;
}

bool Check(int v) {
    int pre=a[1]-v;
    for(int i=2;i<=n;i++) {
        if(a[i]+v<pre) return 0;
        pre=Max(a[i]-v,pre);
    }
    return 1;
}

int main() {
    scanf("%d%d%d%d%d%d%d",&n,&sa,&sb,&sc,&sd,&a[1],&MOD);
    for(int i=2;i<=n;i++) a[i]=(F(a[i-1])+F(a[i-2]))%MOD;
    int l=0,r=1000000007,mid;
    while(l<=r) {
        mid=l+r>>1;
        if(Check(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%d",ans);
    return 0;
}

Bzoj3614逻辑判断

我们将对应的值带入后解多元方程。

代码 :(递归解方程)

//That‘s right ,I am killer .
#include<bits/stdc++.h>
#define LL int
#define eps 1e-9
#define INF 0x3f3f3f3f
using namespace std;

#define int int
inline int Max(int a,int b) {return a>b?a:b;}
inline int Min(int a,int b) {return a<b?a:b;}
inline int Sqr(int a) {return a*a;}
inline int Abs(int a) {return a>0?a:-a;}
#undef int

#define MAXN 1050000

inline int read() {
    int ret=0,f=1,re=2;char c=getchar();
    while(c<‘0‘||c>‘9‘) {if(c==‘-‘) f=-f;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘) {ret=ret*10+c-‘0‘;c=getchar();}
    if(c==‘.‘) {
        c=getchar();
        while(c>=‘0‘&&c<=‘9‘) {ret=ret*10+c-‘0‘;re--;c=getchar();}
    }
    while(re--) ret=ret*10;
    return ret*f;
}
int buf[15],bf;
inline void out(int v) {
    if(v<0) {putchar(‘-‘);v=-v;}
    while(v) {buf[++bf]=v%10;v/=10;}
    while(bf) putchar(buf[bf--]+‘0‘);
}

int n;
struct Frac{
    LL s,m;

    Frac() {s=0;m=1;}

    inline void Refix() {
        LL t=Gcd(Abs(s),Abs(m));
        s/=t;m/=t;
        if(m<0) m=-m,s=-s;
    }
    inline void Init(int a,int b) {
        s=a;m=b;Refix();
    }
    inline void Out() {
        if(s==0) return;
        else if(m==1) out(s);
        else {out(s);putchar(‘/‘);out(m);}
    }

    inline LL Gcd(LL a,LL b) {
        LL t;
        while(b) {t=a%b;a=b;b=t;}
        return a;
    }
    inline LL Lcm(LL a,LL b) {
        return a/Gcd(a,b)*b;
    }

    Frac operator + (Frac x) {
        Frac ret;
        ret.m=Lcm(x.m,m);
        ret.s=ret.m/m*s+ret.m/x.m*x.s;
        ret.Refix();
        return ret;
    }
    Frac operator * (Frac x) {
        Frac ret;
        ret.m=m/Gcd(m,x.s)*(x.m/Gcd(s,x.m));
        ret.s=s/Gcd(s,x.m)*(x.s/Gcd(m,x.s));
        ret.Refix();
        return ret;
    }
};
struct Pa{
    int st;Frac v;
}q[MAXN];
inline bool cmp(const Pa &a,const Pa &b) {
    return a.st<b.st;
}

char s[25];

void Solve(int l,int r) {
    if(l==r) return;
    int mid=l+r>>1;Frac a,b,c;c.Init(1,2);
    for(int i=mid-l;~i;i--) {
        a=q[l+i].v;b=q[mid+i+1].v;
        q[mid+i+1].v=(a+b)*c;a.s=-a.s;
        q[l+i].v=(a+b)*c;
    }
    Solve(l,mid);Solve(mid+1,r);
}

int stk[25],top;bool mk[MAXN];
void Ansout(int p,int l,int r) {
    if(l>r) return;
    if(!mk[r]) {
        q[r].v.Out();
        if(q[r].v.s!=0) {
            if(top) putchar(‘ ‘);
            for(int i=1;i<=top;i++) {putchar(‘x‘);out(stk[i]);}
            printf("\n");
        }
        mk[r]=1;
    }
    if(l==r) return;
    int mid=l+r>>1;
    stk[++top]=p;Ansout(p+1,l,mid);
    top--;Ansout(p+1,mid+1,r);
}

int main() {
    scanf("%d",&n);
    for(int i=1<<n;i;i--) {
        scanf("%s",s);
        q[i].v.Init(read(),100);
        for(int j=0;j<n;j++) if(s[n-j-1]==‘+‘) q[i].st+=1<<j;
    }
    sort(q+1,q+(1<<n)+1,cmp);
    Solve(1,1<<n);
    Ansout(1,1,1<<n);
    return 0;
}

时间: 2024-08-01 20:19:03

Heoi2014系列题解的相关文章

hbx的毒瘤贪心系列题解

毒瘤hbx的贪心专题系列题解 A Maximal gcd 题意:现在给定一个正整数 n.你需要找到 k 个严格递增的正整数a1,?a2,?...,?ak,满足他们的和等于 n 并且他们的最大公因数尽量大.如果不可能请输出 -1.\(1\leq n,k \leq 10^{10}\) 题解:把 n 的所有因子找出来后,求最大因子 x 满足\(x* \frac {k* (k+1)}{2}\leq n\)即可.序列就是\(1* x,2* x,...,(k-1)* x,n-x* \frac{k* (k-1

SPOJ_QTREE系列题解

QTREE4 #pragma comment(linker, "/STACK:102400000,102400000") //#include<bits/stdc++.h> #include <ctime> #include <iostream> #include <assert.h> #include <vector> #include <queue> #include <cstdio> #inclu

[Leetcode] Sum 系列

Sum 系列题解 Two Sum题解 题目来源:https://leetcode.com/problems/two-sum/description/ Description Given an array of integers, return indices of the two numbers such that they add up to a specific target. You may assume that each input would have exactly one sol

BZOJ 4030: [HEOI2015]小L的白日梦

4030: [HEOI2015]小L的白日梦 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 172  Solved: 39[Submit][Status][Discuss] Description 在某一天,你有了一个女性朋友. 你打算利用k天时间陪她,每天有很多种娱乐方式可供选择,你需要从中选择一种进行(一天只能进行一个项目),比如说一起去看电影.一起去主题公园,一起去逛街等等,一共n种项目.当然每个项目重复太多次你都会觉得无聊,因此第i个项目

Zju1290 Word-Search Wonder(http://begin.lydsy.com/JudgeOnline/problem.php?id=2768)

2768: Zju1290 Word-Search Wonder Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 4  Solved: 2[Submit][Status][Web Board] Description The Pyrates Restaurant was starting to fill up as Valentine McKee walked in. She scanned the crowd for her sister, bro

我又来博客园了

之前自己搞的博客服务器不知道这么了 于是我又来博客园写博客了 看看之前写的sb博客 于是全删了 现在这个博客应该会写一些题解什么的 游记的话我还是会放在foreverpiano.cf这个博客上的 由于我太弱了就没有搞css样式 于是现在博客看起来和chenak的博客差不多 那就差不多吧 upd: 由于博主使用emacs 代码可能略微有些缩进奇怪 拖到Dev格式化一下就可以了(博主的代码应该还是可以看懂的吧233) upddddddddddd: 删除了大量无价值博客,保留了一些. 之后零碎学习笔记

弱省胡策系列简要题解

现在不是非常爽,感觉智商掉没了,就整理一下最近弱省胡策的题目吧. 其实题目质量还是很高的. 如果实在看不懂官方题解,说不定这里bb的能给您一些帮助呢? [弱省胡策]Round #0 A 20%数据,O(n4)傻逼dp. 40%数据,O(n3)傻逼dp. 100%数据,令f(x1,y1,x2,y2)表示从(x1,y1)走到(x2,y2)的路径条数.于是所有路径就是f(1,2,n?1,m)×f(2,1,n,m?1).然而两条路径可能在中间的某个点相交,我们找出最早的交点,并在这个交点互换两条路径的后

Myhchael原创题系列 Mychael vs Kid 【题解】

题目链接 Mychael vs Kid 题解 先说说这题的由来及前身 前身 首先有一个很经典的题目: 维护区间加,查询区间\(gcd\) 如果强行用线段树维护的话,区间加之后就没法直接确定当前区间的\(gcd\),不可直接维护 这个时候就用到了\(gcd\)的一个性质: \[(a,b) = (a - b,b)\] 三个的\(gcd\)也是符合的: \[(a,b,c) = (a,b,c - b) = (a,b - a,c - b)\] 同样可以推广出\(n\)个的情况 \[gcd\{a_i\} =

【题解】吉哥系列故事——恨7不成妻

\(Description:\) 给出区间 \([L,R]\) 求出区间中所有满足没有 \(7\) 这个数并且这个数不会被 \(7\) 整除,同时这个数各位上的和不能被 \(7\) 整除.求 \([L,R]\) 的区间中满足这些条件的数的平方和. \(Sample\) \(Input:\) 3 1 9 10 11 17 17 \(Sample\) \(Output:\) 236 221 0 \(Solution:\) 这题老好玩了,坑了我一个早上,发现他要咱们求得是平方和. 好像不可做的样子,看