【学长虐学弟欢乐赛系列】Round4

第四套题

出题人:Bakser

神犇地址:Bakser学长的blog

试题下载地址

数据下载地址

T1 LICS

有一天 Bakser 在做数学题,对于一道题他验算了 n 遍,得到了 n

个结果。无聊的他将这 n 个结果排成了一个圆环,无聊的他又想求这

个环的最长上升子序列。

请你回答这个无聊的问题。

所谓环的上升子序列,指的是从某个位置开始, 按照顺时针顺序

读这个环,得到一个线性序列,它的上升子序列也是这个环的上升子

序列。最长上升子序列是它们中最长的一个。

输入格式:

第一行一个数 n,表示有多少个元素。 第二行 n 个数, ai 表示从位

置 1 开始按顺时针顺序读这个环读到的第 i 个数是什么。

输出格式:

一行,一个数表示最长上升子序列长度。

样例输入:

5

1 2 3 4 5

样例输出:

5

数据范围:

对于 30%的数据, n≤1000

对于 100%的数据, n≤50000,1≤ai≤109

所有数据均为随机生成

专门从国外论文上找来题虐我们真是…跪了

全场比赛就靠这个题骗了30分233

还好8s时限写个普通暴力也能得分

标算太神

听说美国80年代开始研究这东西结果一样的O(nn√logn)算法一场比赛被神犇们搞出来了Orz

//std by Bakser
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int N(5e4+200);
typedef pair<int,int> pii;
int n,a[N],b[N],x[N],t[N],top,f1[N],f2[N];
inline int find(int s){
    int len(0);
    memset(x,0x7f,sizeof(x));x[0]=0;
    for(int i(0);i<n;i++){
        int pos;
        if(i<=n-s)pos=s+i;
        else pos=i-n+s;
        int p=lower_bound(x,x+len+1,a[pos])-x;
        while(x[p]>=a[pos])p--;
        if(a[pos]<x[p+1])
            x[p+1]=a[pos],t[p+1]=pos,len+=(p==len);
    }
    return len;
}
inline int b_s(int l,int r,int val){
    int res=0;
    for(;l<=r;){
        int mid(l+r>>1);
        if(x[mid]>val)l=mid+1,res=max(res,mid);
        else r=mid-1;
    }
    return res;
}
int main(){
    freopen("LICS.in","r",stdin);
    freopen("LICS.out","w",stdout);
    scanf("%d",&n);
    for(int i(1);i<=n;i++)scanf("%d",a+i);
    int len=find(1),ans=len;
    for(int i(1);i<=len;i++){
        int l=0,p(0),last(0);
        memset(f1,0,sizeof(f1));
        memset(f2,0,sizeof(f2));
        memset(x,0x7f,sizeof(x));x[0]=0;
        for(int j(0);j<n;j++){
            p=(t[i]+j)%n;
            if(!p)p=n;
            f1[p]=0;
            if(a[p]>=a[t[i]]){
                int t=lower_bound(x,x+l+1,a[p])-x;
                while(x[t]>=a[p])t--;
                if(a[p]<x[t+1])
                    x[t+1]=a[p],l+=(t==l);
                f1[p]=t+1;
            }
            f1[p]=max(f1[p],f1[last]);
            last=p;
        }
        l=0;memset(x,0,sizeof(x));x[0]=0x7fffffff;
        for(int j(0);j<n;j++){
            p=(t[i]-j+n)%n;
            if(!p)p=n;
            f2[p]=0;
            if(a[p]<=a[t[i]]){
                int t=b_s(0,l,a[p]);
                if(a[p]>x[t+1])
                    x[t+1]=a[p],l+=(t==l);
                f2[p]=t+1;
            }
            f2[p]=max(f2[p],f2[last]);
            last=p;
        }
        for(int i(1);i<=n;i++)
            ans=max(ans,f1[i]+f2[i%n+1]-1);
    }
    printf("%d\n",ans);
    return 0;
}

T2 Tree

Bakser 得到了一棵无根树,每个节点上有一个权值, 他决定在这

棵树上逗比。设这棵树上从 u 到 v 的路径长度为 l,这条路径上的点

权 构 成 一 个 序 列 {z0,? z1…zl } 。 则 这 条 路 径 的 权 值 定 义 为

z0 × k0 +? z1 ×? k1 +?…?+? zl ×? kl。如果这条路径的权值 MOD Y 等于 X,则

称这条路径为逗比的。否则称它为高冷的。

他想出了一个结论,如果路径(u,t)和(t,v)是逗比的,则路径(u,v)一

定是逗比的。如果路径(u,t)和(t,v)是高冷的,则路径(u,v)一定是高冷的。

显然这个结论是错的,但高冷(dòu bī)的他才不会承认这个结论是

错的,请你统计对于给定的树, 有多少个满足这个结论的三元组(u,t,v)。

输入格式:

第一行四个数 n、 Y、 k、 X, n 是这棵树的点数, Y、 k、 X 的含义如

题目描述所示。

第二行 n 个数: v1 、 v2……vn,。 vi 表示节点 i 的权值。

接下来 n-1 行, 每行两个数 u、 v, 表示存在一条从 u 到 v 的无向

边。

输出格式:

一行,一个数表示满足题目条件的三元组数目 。

样例输入:

3 5 2 1

4 3 1

1 2

2 3

样例输出:

14

数据范围:

对于 30%的数据, n≤100

对于 60%的数据, n≤1000

对于 100%的数据, n≤100000 , 2?≤ Y?≤? 109; 1?≤? k <? Y; 0?≤? X <? Y

考试时候看出来是点分治了但是不会点分治= =

后来写了链剖代替

再后来就写残了

看来链剖果然不是正确姿势QAQ

枚举三元组太蛋疼= =标算的代替方法看得我醉了

100分算法就是在这个基础上加上了点分治而已

//std by Bakser    点分治好可怕比我链剖还长
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <climits>
#include <vector>
#include <map>
using namespace std;
const int N(1e5+200);
typedef long long LL;
typedef vector<int>::iterator iter;
#define MAX(a,b) (((a)>(b))?(a):(b))
template<class T>
inline void read(T &x){
    char c=0;
    for(;c<‘0‘||c>‘9‘;c=getchar());
    for(x=0;c>=‘0‘&&c<=‘9‘;c=getchar())x=(x*10+(c-‘0‘));
}
int n,w[N],X,K,MOD,point[N],sz[N],f[N],in[N],ou[N],up[N],need[N],down[N],rot,pw[N],inv[N],q[N],top,dep[N];
struct hh{int next,v;}edges[N*2];
bool vis[N];
LL ans(0);
vector<int> son[N];
map<int,int>from,to;
inline void addedge(int u,int v){
    static int en(0);
    edges[++en].next=point[u];point[u]=en;
    edges[en].v=v;
}
inline LL power(LL x,LL k){
    LL res(1);
    for(;k;k>>=1){
        if(k&1)res=res*x%MOD;
        x=x*x%MOD;
    }
    return res;
}
inline void dfs_sz(int x,int fa){
    sz[x]=1;f[x]=0;q[++top]=x;
    for(int i(point[x]);i;i=edges[i].next)
        if(!vis[edges[i].v]&&edges[i].v!=fa){
            int v(edges[i].v);
            dfs_sz(v,x);
            sz[x]+=sz[v];
            f[x]=MAX(f[x],sz[v]);
        }
}
inline int find_focus(int x){
    top=0;dfs_sz(x,0);
    int res,tmp(INT_MAX);
    for(int i(1);i<=top;i++){
        int t=MAX(sz[x]-sz[q[i]],f[q[i]]);
        if(t<tmp)tmp=t,res=q[i];
    }
    return res;
}
inline void dfs(int x,int fa){
    for(int i(point[x]);i;i=edges[i].next)
        if(!vis[edges[i].v]&&edges[i].v!=fa){
            int v(edges[i].v);
            dep[v]=dep[x]+1;
            up[v]=((LL)up[x]*(LL)K%MOD+(LL)w[v])%MOD;
            down[v]=(down[x]+(LL)w[v]*(LL)pw[dep[v]])%MOD;
            dfs(v,x);
        }
}
inline void get_sons(int x,int fa,int anc){
    son[anc].push_back(x);
    for(int i(point[x]);i;i=edges[i].next)
        if(!vis[edges[i].v]&&edges[i].v!=fa)
            get_sons(edges[i].v,x,anc);
}
inline int ask(map<int,int> &m,int x){
    if(m.count(x))return m[x];
    return 0;
}
inline void add(map<int,int> &m,int x,int f){
    if(m.count(x))m[x]+=f;
    else m[x]=f;
}
inline void calc(){
    from.clear();to.clear();
    for(int i(1);i<=top;i++)
        for(iter j=son[q[i]].begin();j!=son[q[i]].end();j++)
            add(to,down[*j],1);
    for(int i(1);i<=top;i++){
        vector<int> &x=son[q[i]];
        for(iter j=x.begin();j!=x.end();j++)
            add(to,down[*j],-1);
        for(iter j=x.begin();j!=x.end();j++){
            ou[*j]+=ask(to,need[*j]);
            in[*j]+=ask(from,down[*j]);
        }
        for(iter j=x.begin();j!=x.end();j++)
            add(from,need[*j],1);
    }
}
inline void solve(int x){
    vis[x=find_focus(x)]=1;
    up[x]=down[x]=w[x];dep[x]=0;
    dfs(x,0);
    for(int i(1);i<=top;i++)
        if(q[i]==x){if(up[x]==X)ou[x]++,in[x]++;}
        else{
            if(up[q[i]]==X)in[x]++,ou[q[i]]++;
            if(down[q[i]]==X)ou[x]++,in[q[i]]++;
        }top=0;
    for(int i(point[x]);i;i=edges[i].next)
        if(!vis[edges[i].v]){
            int v(edges[i].v);
            q[++top]=v;son[v].clear();get_sons(v,0,v);
            for(iter j=son[v].begin();j!=son[v].end();++j)
                need[*j]=((X-up[*j]+MOD)*(LL)inv[dep[*j]]+w[x])%MOD;
        }
    calc();
    reverse(q+1,q+top+1);
    calc();
    for(int i(point[x]);i;i=edges[i].next)
        if(!vis[edges[i].v])
            solve(edges[i].v);
}
int main(){
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    read(n);read(MOD);read(K);read(X);
    for(int i(1);i<=n;i++)read(w[i]);
    for(int i(1),u,v;i<n;i++){
        read(u);read(v);
        addedge(u,v);
        addedge(v,u);
    }
    for(int i(pw[0]=1);i<=n;i++){
        pw[i]=(pw[i-1]*(LL)K)%MOD;
        inv[i]=power(pw[i],MOD-2);
    }f[0]=INT_MAX;
    solve(1);
    for(int i(1);i<=n;i++){
        ans+=((LL)in[i]*LL(n-in[i]))<<1;
        ans+=((LL)ou[i]*LL(n-ou[i]))<<1;
        ans+=(LL)in[i]*LL(n-ou[i])+(LL)ou[i]*LL(n-in[i]);
    }
    ans=(LL)n*n*n-(ans>>1);
    cout<<ans<<endl;
    return 0;
}

T3 Circle

Bakser 是一个大蒟蒻,有一天他随手画了一个 n 个点的环状图。

他觉得只有一个环不美观就又在中间加了一个点,并从环上的 n 个点

分别向中间这个点引了一条边。

现在他想知道这个 n+1 个点的图有多少种不同的生成树。

每个点被认为是本质相同的,所以两个生成树被认为是相同的,

当且仅当这两个生成树经过旋转可以完全重合。

但良心的他觉得上面那个条件太丧病了,所以在某些数据中你不

必考虑它。

输入格式:

一行三个正整数: n,m,f。 n 表示环上的点数(即整个图一共 n+1

个点) m 表示答案对 m 取模。 f 为 1 时表示不需要考虑旋转同构,为

0 时表示需要考虑。

输出格式:

一行一个数,表示答案对 m 取模后的结果。

样例输入:

1 2333333 1

样例输出 :

1

数据范围:

数据点编号

1-3 n≤100 m≤109 f=1

4-5 n≤108 m≤109 f=1

6-7 n≤105 m≤109 f=0

8-10 n≤109 m≤109 f=0

一直想用组合数学做这个题

还是没做出来…

Sunshine神犇打表找规律过50%真是太神了OTZ

50分正确姿势Matrix-Tree定理好像大家都不爱他

递推式太神OTZ

(P.S.知道了也写不好…因为不会写矩阵乘)

同构使用群论解决

为什么觉得有点像→Longge的问题

//std by Bakser
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N(1e9);
const int M(40000);
int n,phi[M],prime[M],tot;
bool vis[M];
LL MOD;
inline LL mul(LL a,LL b){
    LL res=0;
    a=(a%MOD+MOD)%MOD;
    b=(b%MOD+MOD)%MOD;
    for(;b;b>>=1){
        if(b&1)res=(res+a)%MOD;
        a=(a<<1)%MOD;
    }
    return res;
}
struct Mat{
    LL a[2][2];
    inline Mat operator *(const Mat &b)const{
        Mat c;
        for(int i(0);i<2;i++)
            for(int j(0);j<2;j++){
                c.a[i][j]=0;
                for(int k(0);k<2;k++)
                    c.a[i][j]=(c.a[i][j]+mul(a[i][k],b.a[k][j]))%MOD;
            }
        return c;
    }
}base;
inline Mat power(Mat a,int k){
    Mat res;
    for(int i(0);i<2;i++)
        for(int j(0);j<2;j++)
            res.a[i][j]=(i==j);
    for(;k;k>>=1){
        if(k&1)res=res*a;
        a=a*a;
    }
    return res;
}
inline void sieve(){
    for(int i(2);i<=M;i++){
        if(!vis[i])prime[++tot]=i;
        for(int j(1);j<=tot&&i*prime[j]<=M;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)break;
        }
    }
}
inline LL get_phi(int n){
    LL res(n);
    for(int i(1);i<=tot&&prime[i]*prime[i]<=n;i++)
        if(n%prime[i]==0){
            res=res/prime[i]*(prime[i]-1);
            while(n%prime[i]==0)n/=prime[i];
        }
    if(n>1)res=res/n*(n-1);
    return res%MOD;
}
inline LL get_T(int k){
    if(k==1)return 1;
    if(k==2)return 5;
    Mat t=power(base,k-2);
    LL f=((3*t.a[0][0])%MOD+t.a[1][0])%MOD;
    LL g=(2*(((f-(3*t.a[0][1]+t.a[1][1])-1)%MOD+MOD)%MOD))%MOD;
    return (g+f)%MOD;
}
inline LL calc(){
    LL res=0;
    for(int i(1);i*i<=n;i++)
        if(n%i==0){
            res=(res+mul(get_phi(i),get_T(n/i)))%MOD;
            if((n/i)!=i)res=(res+mul(get_phi(n/i),get_T(i)))%MOD;
        }
    return res/n;
}
int main(){
    freopen("circle.in","r",stdin);
    freopen("circle.out","w",stdout);
    sieve();int ff=0;
    base.a[0][0]=3;base.a[0][1]=1;base.a[1][0]=-1;base.a[1][1]=0;
    scanf("%d%I64d%d",&n,&MOD,&ff);
    if(ff)printf("%I64d\n",get_T(n));
    else{
        MOD=(LL)n*MOD;
        printf("%I64d\n",calc()%(MOD/n));
    }
    return 0;
}

最后暴力分也没得全QAQ

再也不看见题就瞎写链剖了QAQ

时间: 2024-10-07 07:06:33

【学长虐学弟欢乐赛系列】Round4的相关文章

【学长虐学弟欢乐赛系列】Round1

第一套题 出题人:Time-Machine 目标地址:Time-Machine学长的blog 试题下载地址 数据下载地址 据说题目难度T3<T1<T2 这不科学QAQ 光荣爆零QwQ奇怪的错误是说不尽的 T1 Hope 主要题干:首先你列出了两个长度为 n 的数表 a[],b[],其中每个数 a[i]用二进制表示一个集合.例如数字 5=( 101) 2 就代表集合{1,3}.第 i 次实验会准备一个小盒子,里面装着集合 a[i]所有非空子集的纸条,然后苗木诚会从中摸一张纸条.如果满足他摸的这张

【学长虐学弟欢乐赛系列】Round2

第二套题 出题人:Lavender 神犇地址:Lavender学姐的blog 试题下载地址 数据下载地址 T1 matrix **主要题干:**Neo 会干很多事,除了跑暴力程序看视频之外,还会做出去玩玩 和用鼠标乱点之类的事,甚至会一脚踢掉电源--这些事有的会让做 这件事的这段时间内 CPU 使用率增加或减少一个值:有的事还会直 接让 CPU 使用率变为一个值. 当然 Neo 会询问:在之前给出的事件影响下, CPU 在某段时间内, 使用率最高是多少.有时候 Neo 还会好奇地询问,在某段时间

【学长虐学弟欢乐赛】Round3

第三套题 出题人:faebdc 金牌爷的题这么神竟然还有学长AK了QAQ 题目全都是CF上的 T1 D T2 E T3 D 神犇地址:faebdc学长的blog 试题下载地址 数据下载地址 话说题解的ppt用色果然还是faebdc神犇的常用配色= = 虚化色块喷涂拼接 T1 CF305D Olya ans Graph 原题可以自己去CF找 学长给的是翻译后题面 [问题描述] Olya 有一张 n 个点. m 条边的有向无权图, 所有点从 1 到 n 标号. 现在 Olya 想知道 有多少种添加有

2014考研复试漫谈 --致考研刚刚结束的学弟学妹

回忆1( 成绩出来前): 去年考完研的时候,自己对于考上没有多大的把握,所以,考完研决定要做两手准备:一边准备复习,一边为找工作而准备着. 好像大学过的最紧张的日子莫过于此,因为眼看着周围的同学都纷纷出去找工作,并且有的同学还找到了不错的工作.自己现在考研占据了大量的时间,已经错过了所谓的找工作的黄金期,同时觉得自己的专业技能也不是很强,所以很担心自己万一考不上了,工作也不好找.那就真成了没人要的孩子了.没有什么比前途未卜更令人担忧了...所以,大过年的,我还在看王道新出的一本面试宝典,在巩固自

欢乐赛解题报告

~~一场不欢乐的欢乐赛 时间分配::T1做的时候还可以,大约三十分钟写了个深搜(鬼知道我为啥不用广搜,大概是因为快半个月没写了)写完后去研究第二题,刚开始以为是贪心,很快写了出来,但是自己推了一会举出了反例.于是自己想了很多方法,但是都是基于贪心,写了一个多小时,写炸了,没办法又改成了贪心.第三题并不会,然后搜索大法过了一个点,(输出-1也是一个点) 整体感觉::还是太弱,T1是会的,但是还是没做对,大概是独立做题少的缘故吧,平常做题都没有思考太多时间.T2贪心T3暴力,貌似自己啥都不会.到现在

程序员的奋斗史(四十六)——大学断代史(十)——给学弟学妹们的忠告——终结篇

文/温国兵 「写在前面」 大学断代史终于要完结了,就像一条再长的路总有终点一样.该系列文章前前后后写了一两个月,也该收尾了,至于收尾的文章,想了想,决定写写自己对学弟学妹的忠告.本篇文章以话题的形式呈现. 「关于专业」 我相信大多数的读者在高考填志愿都不知道软件工程或者计算机专业是做啥的,稀里糊涂就踏上了这条IT不归路.身处小乡村,消息相对闭塞,能使用电脑都是奢侈的事情,这就是当初我高考后的境况,相信现在有很大的改变.如果你对IT行业抱有一番热情,恭喜你,选对了好专业,好好学,今后的路错不了.如

对学弟学妹的建议

在大学这四年我感觉自己是个失败者,在大学即将结束时留下了许多的遗憾.希望学弟学妹们能利用好大学四年,不能说没有遗憾,遗憾尽量的少一些吧. 学会利用大学里的资源. 老师.图书馆.身边的同学以及师兄.师姐他们都是你大学期间有形的宝贵资源.老师.师兄和师姐他们是你的长辈,能为你指导未来的方向和解决你大部分的学习和生活上的一些困惑.图书馆是你课下学习.扩展眼界.阅读各种杂书的好地方.身边的同学和你有着很多的相似点,他们也许和你有着相同的困惑,在大学期间把握和同学在一起的时光,因为他们有可能是你一辈子的朋

写给即将毕业的学弟学妹们!

1.Spring Security 目前支持认证一体化如下认证技术: HTTP BASIC authentication headers (一个基于IEFT  RFC 的标准) HTTP Digest authentication headers (一个基于IEFT  RFC 的标准) HTTP X.509 client certificate exchange  (一个基于IEFT RFC 的标准) LDAP (一个非常常见的跨平台认证需要做法,特别是在大环境) Form-based auth

11th 回忆整个学期——告学弟学妹

告诉后来的学弟学妹,不要因为艰难而却步,坚持下去才知道,山的对面是什么.很多东西或许一开始看起来是无用,甚至无意义的,但是努力去做,你才知道价值所在.不要等一切结束了,才懂得自己错过了什么.