标签:随便搞搞
第四套题 
出题人:Bakser 
神犇地址:Bakser学长的blog 
试题下载地址 
数据下载地址 
T1 LICS 
有一天 Bakser 在做数学题,对于一道题他验算了 n 遍,得到了 n 
个结果。无聊的他将这 n 个结果排成了一个圆环,无聊的他又想求这 
个环的最长上升子序列。 
请你回答这个无聊的问题。 
所谓环的上升子序列,指的是从某个位置开始, 按照顺时针顺序 
读这个环,得到一个线性序列,它的上升子序列也是这个环的上升子 
序列。最长上升子序列是它们中最长的一个。 
输入格式: 
第一行一个数 n,表示有多少个元素。 第二行 n 个数, ai 表示从位 
置 1 开始按顺时针顺序读这个环读到的第 i 个数是什么。 
输出格式: 
一行,一个数表示最长上升子序列长度。 
样例输入: 
5 
1 2 3 4 5 
样例输出: 
5 
数据范围: 
对于 30%的数据, n
对于 100%的数据, n
所有数据均为随机生成 
专门从国外论文上找来题虐我们真是…跪了 
全场比赛就靠这个题骗了30分233 
还好8s时限写个普通暴力也能得分 
标算太神 
 
 
 
听说美国80年代开始研究这东西结果一样的O(n
//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,这条路径上的点 
权 构 成 一 个 序 列 {z
z
称这条路径为逗比的。否则称它为高冷的。 
他想出了一个结论,如果路径(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
对于 60%的数据, n
对于 100%的数据, n
考试时候看出来是点分治了但是不会点分治= = 
后来写了链剖代替 
再后来就写残了 
看来链剖果然不是正确姿势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
4-5 n
6-7 n
8-10 n
一直想用组合数学做这个题 
还是没做出来… 
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
标签:随便搞搞
原文地址:http://blog.csdn.net/creationaugust/article/details/44039589