[20180811]校内模拟赛

T1 二元组(pair)

题目描述

求有多少个非负整数二元组(x,y)满足xy+x+y=n。

输入格式

输入文件pair.in

多组数据,第一行一个整数T表示数据组数。

接下来T行,每行一个非负整数n,表示一个询问。

输出格式

输出文件pair.out

输出T行,每行一个整数,表示答案。

样例

样例输入

3
1
3
4

样例输出

2
3
2

数据范围与提示

对于30%的数据,n≤20000,T≤1000;

对于100%的数据,n≤10^8,T≤10000。

Solution

把原式转化成\((x+1)(y+1)=n+1\),所以只要枚举\(n+1\)的因数就可以了。

#include<cstdio>
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
int T,n,ans,flag;
int main(){
    freopen("pair.in","r",stdin);
    freopen("pair.out","w",stdout);
    T=read();
    register int i;
    while(T--){
        n=read()+1;ans=0;flag=0;
        for(i=1;i*i<n;i++){
            if(n%i==0) ans++;
        }
        if(i*i==n) flag=1;
        printf("%d\n",(ans<<1)+flag);
    }
    return 0;
}

T2 排列计数(permutation)

题目描述

求有多少个1到n的排列满足恰有k对在排列中相邻的数满足前小于后,答案对2012取模。

输入格式

输入文件permutation.in

一行2个正整数n,k。

输出格式

输出文件permutation.out

输出一个整数表示答案。

样例

样例输入

5 2

样例输出

66

数据范围与提示

对于30%的数据,n≤10。

对于100%的数据,k<n≤1000。

Solution

当初的做法时一个\(O(kn^3)\)的加上一个前缀和优化,卡过了70分。

正解:用f[i][j]表示当n=i,k=j时的方案数,考虑往i的排列中插入一个i+1,插在什么位置会让j加1,容易得到
\[ f[i][j]=(i+1)*f[i-1][j]+(i-j)*f[i-1][j-1] \]

#include<cstdio>
#include<cstring>
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
#define MN 1005
#define mod 2012
int n,K,ans;
//int f[2][MN][MN][3];
int f[MN][MN]; 
inline void add(int &x,int y){x+=y;x%=mod;}
int main(){
    freopen("permutation.in","r",stdin);
    freopen("permutation.out","w",stdout);
    n=read(),K=read();
/*暴力dp-70分 
    register int i,j,k,kk,now=0;
    f[0][1][0][0]=1;
    for(i=2;i<=n;i++){
        now=1-now;
        memset(f[now],0,sizeof f[now]);
        f[now][0][1][0]=f[now][i-1][i][0]=1;
        for(j=1;j<i-1;j++)for(k=i-1;k>=1;k--)
            add(f[now][j][k][1],f[1-now][j][k][0]+f[now][j][k+1][1]);
        for(j=1;j<i-1;j++)for(k=2;k<=i;k++)
            add(f[now][j][k][2],f[1-now][j-1][k-1][0]+f[now][j][k-1][2]);
        for(j=1;j<i-1;j++)for(k=1;k<=i;k++)
            add(f[now][j][k][0],f[now][j][k][1]+f[now][j][k][2]);
    }
    for(i=1;i<=n;i++) add(ans,f[now][K][i][0]);
    printf("%d\n",ans);
*/
    register int i,j;
    f[1][0]=f[2][0]=f[2][1]=1;
    for(i=3;i<=n;i++){
        f[i][0]=f[i][i-1]=1;
        for(j=1;j<i-1;j++) f[i][j]=((j+1)*f[i-1][j]%mod+f[i-1][j-1]*(i-j)%mod)%mod;
    }
    printf("%d\n",f[n][K]);
    return 0;
}

T3 最短路(shortest)

题目描述

给出一个n个点m条边的无向图,点编号为1到n。定义最短路树为一个边集满足恰好构成一棵n个点的树且1号点在树上到每个点的最短路等于其在原图中的最短路。

给出最短路树,对除了1号点外的每个点i求从1号点出发且不经过最短路树上1到i最短路径上最后一条边的最短路长度。

输入格式

输入文件shortest.in

第一行两个正整数n,m。

接下来m行,每行四个非负整数a,b,l,t,表示有一条连接a和b且长度为l的边,若t=1,这条边为最短路树上的边;若t=0则不是最短路树上的边。

输出格式

输出文件shortest.out

输出一行n−1个数,第i个表示1到i+1要求的答案,如果无解则输出-1

样例

样例输入

5 9
3 1 3 1
1 4 2 1
2 1 6 0
2 3 4 0
5 2 3 0
3 2 2 1
5 3 1 1
3 5 2 0
4 5 4 0

样例输出

6 7 8 5

数据范围与提示

对于30%的数据,n≤100,m≤2000。

对于100%的数据,n≤4000,m,l≤10^5。

Solution

原题时BZOJ的3694。

到点i的最优路径必然是先沿树边走到子树i以外的一个点,再走一条非树边进子树i,然后沿树边走到i。枚举一条a走到b长度为L的边,a在子树外b在子树内,对点i的贡献是d[a]+L+d[b]-d[i],由于-d[i]只跟i有关,只要对一个i求满足条件的最小的d[a]+L+d[b]

怎么求呢。根据最优路径的走法,对于一对a和b,其实只会影响到a、b到lca(a,b)(不包括lca)的两条链,把所有的d[a]+L+d[b]按照大小排序后,一旦一个节点被更新后,就不会再被更新。用并查集维护,将被跟新后的链上元素全部指向链顶,这样就可以轻松地从a,b往lca上跳,且不会更新哪些已经被赋值地节点了。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
#define MN 4005
#define ME 100005 
struct edge{int to,w,nex;}e[MN<<1];int cnt=0,hr[MN];
inline void ins(int f,int t,int w){
    e[++cnt]=(edge){t,w,hr[f]};hr[f]=cnt;
    e[++cnt]=(edge){f,w,hr[t]};hr[t]=cnt;
} 
int n,m,dis[MN],Fa[MN],f[MN],bel[MN],dep[MN],pin;
struct relation{int a,b,w;}re[ME];
bool cmp(relation M,relation N){return M.w<N.w;}
void dfs(int fa,int x){
    for(int i=hr[x];i;i=e[i].nex)if(e[i].to^fa){
        Fa[e[i].to]=x;dis[e[i].to]=dis[x]+e[i].w;dep[e[i].to]=dep[x]+1;dfs(x,e[i].to);
    }
}
int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);} 
int main(){
    freopen("shortest.in","r",stdin);
    freopen("shortest.out","w",stdout);
    n=read(),m=read();
    register int i,j,x,y,l,t;
    for(i=1;i<=m;i++){
        x=read(),y=read(),l=read(),t=read();
        if(t) ins(x,y,l);
        else re[++pin]=(relation){x,y,l};
    }
    dis[1]=0;dep[1]=1;dfs(0,1);
    for(i=1;i<=n;i++) f[i]=i;
    for(i=1;i<=pin;i++) re[i].w+=dis[re[i].a]+dis[re[i].b];
    sort(re+1,re+pin+1,cmp);
    for(i=1;i<=pin;i++){
        int x=getf(re[i].a),y=getf(re[i].b);
        while(x^y){
            if(dep[x]<dep[y]) swap(x,y);
            bel[x]=i;
            x=f[x]=getf(Fa[x]);
        }
    }
    for(i=2;i<=n;i++){
        if(bel[i]) printf("%d ",re[bel[i]].w-dis[i]);
        else printf("-1 ");
    }
    return 0;
}

Blog来自PaperCloud,未经允许,请勿转载,TKS。

转载于:https://www.cnblogs.com/PaperCloud/p/9461818.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值