小 W 摆石子
【问题描述】
小 W 得到了一堆石子,要放在 N 条水平线与 M 条竖直线构成的网格的交点上。因为小 M 最喜欢矩形了,小 W 希望知道用 K 个石子最多能找到多少四边平行于坐标轴的长方形,它的四个角上都恰好放着一枚石子。
【输入格式】
第一行三个整数 N,M,K。
【输出格式】
一个非负整数,即最多的满足条件的长方形数量。
【输入输出样例】
rectangle.in
3 3 8
rectangle.out
5
rectangle.in
7 14 86
rectangle.out
1398
【数据规模】
对于 50%的数据:N<=30
对于 100%的数据:N<=30000,保证任意两点不重合,K<=N*M
题解
暴力枚举即可
#include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; long long n,m,k,sum,ans; long long C(long long x){return x*(x-1)>>1;} long long maxx(long long a,long long b){return a>b?a:b;} long long work(long long x,long long y) { long long i,tans; tans=0; for(i=1;i<=y;i++) if(k/i+(bool)(k%i)<=x) tans=maxx(tans,C(k/i)*C(i)+C(k%i)*(k/i)); return tans; } int main() { int i,j; freopen("rectangle.in","r",stdin); freopen("rectangle.out","w",stdout); scanf("%d%d%d",&n,&m,&k); ans=maxx(work(n,m),work(m,n)); printf("%lld",ans); return 0; }
小 M 玩数列
【问题描述】
众所周知,小 M 的数学超级超级好,于是给小 W 出了一道题:
给小 W 两个数 X,Y,其中 X ≤ Y≤ 2^31−1。
小 W 任务就是求出 Fibonacci 数列第 X~Y 项的和除以 10000 的余数。
然而小 W 是数学战五渣,于是只能把这个任务交给机智的你啦。
【输入格式】
第一行一个整数 T,表示数据组数。
接下来 T 行,每行两个数 X,Y,意义如题所述。
【输出格式】
T 行,每行是一个询问的答案。
【输入输出样例】
fibonacci.in
2
1 5
fibonacci.out
127 255
fibonacci.in
1
12
fibonacci.out
5976
【数据规模】
对于 80%的数据:T=1,Y<=10^6
对于 100%的数据:T<=1000,Y<=2^31-1
题解
矩乘优化即可
#include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<queue> #define mod 10000 using namespace std; struct hh { int a[5][5],n,m; }; hh a,b,c; int t,l,r,suma,sumb,ans; int f[50005]; hh mul(hh,hh); hh ff(hh,int); int main() { int i,j; freopen("fibonacci.in","r",stdin); freopen("fibonacci.out","w",stdout); scanf("%d",&t); a.m=a.n=b.n=3; b.m=1; for(j=1;j<=3;j++) a.a[1][j]=1; a.a[2][2]=a.a[2][3]=1; a.a[3][2]=1; b.a[1][1]=2; b.a[2][1]=b.a[3][1]=1; while(t--) { scanf("%d%d",&l,&r); if(l<=3) suma=l-1; else{c=mul(ff(a,l-3),b);suma=c.a[1][1];} if(r<=2) sumb=r; else{c=mul(ff(a,r-2),b);sumb=c.a[1][1];} ans=(sumb-suma+mod)%mod; printf("%d ",ans); } fclose(stdin); fclose(stdout); return 0; } hh mul(hh a,hh b) { int i,j,k; hh c; c.n=a.n; c.m=b.m; memset(c.a,0,sizeof(c.a)); for(i=1;i<=c.n;i++) for(j=1;j<=c.m;j++) for(k=1;k<=c.n;k++) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod; return c; } hh ff(hh a,int k) { int i,j; hh c; c.m=a.m; c.n=a.n; for(i=1;i<=min(c.n,c.m);i++) c.a[i][i]=1; for(i=1;i<=c.n;i++) for(j=1;j<=c.m;j++) if(i!=j) c.a[i][j]=0; while(k) { if(k&1) c=mul(a,c); a=mul(a,a); k>>=1; } return c; }
小 W 计树
【问题描述】
小 W 千辛万苦做出了数列题,突然发现小 M 被困进了迷宫里。迷宫是一个有 N(2≤N≤1000)个顶点 M(N−1≤M≤N∗(N − 1)/2 ) 条边的无向连通图。设 dist1[i]表示在这个无向连通图中, 顶点 i 到顶点 1 的最短距离。为了解开迷宫,现在要求小 W 在这个图中删除 M − (N − 1)条边,使得这个迷宫变成一棵树。设 dist2[i]表示在这棵树中,顶点 i 到顶点 1 的距离。小 W 的任务是求出有多少种删除方案,使得对于任意的 i,满足 dist1[i]=dist2[i]。
快点帮助小 W 救出小 M 吧!
【输入格式】
第一行,两个整数, N, M,表示有 N 个顶点和 M 条边。
接下来有 M 行,每行有 3 个整数 x, y, len(1 ≤ x, y ≤ n, 1 ≤ len ≤ 100),表示顶点 x 和顶点 y 有一条长度为 len 的边。
数据保证不出现自环、重边。
【输出格式】
一行两个整数,表示满足条件的方案数 mod 2147483647 的答案。
【输入输出样例】
treecount.in
3 3
1 2 2
1 3 1
2 3 1
treecount.in
2
【样例解释】
删除第一条边或第三条边都能满足条件,所以方案数是 2。
【数据规模】
对于 30%的数据:2≤N≤5,M≤10
对于 50%的数据:满足条件的方案数不超过 10000
对于 100%的数据:2≤N≤1000
题解
首先考虑离 1 点最近的那个点,一定和 1 点只连着一条边,则这条边是必选的;然后考察第二近的点,一种可能是和 1 点直接连的边比较近,一种可能是经过刚才最近的那个点再到 1 点的路比较近,不管是哪一种,选择都是唯一的,而剩下第三种可能是两者距离相同,这样的话两者选且只能选一个。以此类推,假设现在已经构造好了前 k 个点的一棵子树,看剩余点中到 1 点最近的点,这个点到 1 点有 k 种方法(分别是和那 k 个点连边), 其中有 m 个是可以保持最短距离的,则这一步可选的边数就是 m。一直构造,把方法数累乘,就能得到最后的结果。整个过程可以很好的符合 dijkstra 的过程,而生成树的步骤和 prim 如出一辙。
#include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<queue> #define mod 2147483647 using namespace std; int n,m; bool v[1005]; int we[1010][1010], dis[1010]; int last[1010]; int tot=0; struct hh { int next,to,w; }e[2000005]; long long ans=1; struct node { int id,d; }; node a[1005]; queue<int> q; bool cmp(node a, node b) { return a.d < b.d; } void add(int a,int b,int c) { tot++; e[tot].to=b; e[tot].w=c; we[a][b]=c; e[tot].next=last[a]; last[a]=tot; } void spfa() { int i,now; for(i=2;i<=n;i++) dis[i]=9999999; q.push(1); dis[1]=0; while(!q.empty()) { now=q.front(); q.pop(); v[now]=false; for(i=last[now];i;i=e[i].next) if(dis[e[i].to]>dis[now]+e[i].w) { dis[e[i].to]=dis[now]+e[i].w; if(!v[e[i].to]) { v[e[i].to]=true; q.push(e[i].to); } } } } int main() { int i,j,x,y,z,now; freopen("treecount.in","r",stdin); freopen("treecount.out","w",stdout); scanf("%d%d",&n,&m); for(i=1;i<=n;i++) for(j=1;j<=n;j++) we[i][j]=9999999; for(i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } spfa(); for (i=1;i<=n;i++) { a[i].id=i; a[i].d=dis[i]; } sort(a+1,a+n+1,cmp); for(i=2;i<=n;i++) { now=0; for(j=1;j<=i-1;j++) if(a[i].d==a[j].d+we[a[i].id][a[j].id]) now++; ans=ans*(long long)now%mod; } printf("%lld",ans); fclose(stdin); fclose(stdout); return 0; }