JZOJ 3084 超级变变变
题目
定义 f [ n ] = f[n]= f[n]=
- n n n是奇数, f [ n ] = n − 1 f[n]=n-1 f[n]=n−1
- n n n是偶数, f [ n ] = n ÷ 2 f[n]=n\div 2 f[n]=n÷2
问经过若干次 n = f [ n ] n=f[n] n=f[n],区间 [ a ∼ b ] [a\sim b] [a∼b]有多少个可以变成 k k k
分析
可以发现, f [ n ] f[n] f[n]的操作实则是把末位改为0或把末位删去,前面是不受影响的,所以也就是在 k k k的二进制位后面添上若干个0或者1,所以可以找到它的区间,统计个数
代码
#include <cstdio>
#define rr register
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
using namespace std;
typedef long long ll;
ll k,a,b,ans;
signed main(){
scanf("%lld%lld%lld",&k,&a,&b);
if (!k) return !printf("%lld",b-a+1);
rr ll l=k,r=k+1-(k&1);
if (l>=a&&l<=b) ++ans;
if (r>=a&&r<=b&&!(k&1)) ++ans;
while (r<=b){
l<<=1; r=r<<1|1;
rr ll l1=max(l,a),r1=min(r,b);
if (l1<=b&&r1>=a&&l1<=r1) ans+=r1-l1+1;
}
printf("%lld",ans);
}
JZOJ 3085 图的计数
题目
询问有多少个N个点,M条边的有向图,从1号点到达N号点需要经过至少N-1条边。该有向图中可以包含重边和自环。
分析
首先, 2 ∼ n − 1 2\sim n-1 2∼n−1的点是可以任意排列的,所以答案要乘 ( n − 2 ) ! (n-2)! (n−2)!,然后、如果求出了最短路,那么如果出现了捷径边,肯定是不可行的,那么这样的边有 C ( n − 2 , 2 ) C(n-2,2) C(n−2,2)条,那么可选的边数就是 n 2 − c ( n − 2 , 2 ) − 1 n^2-c(n-2,2)-1 n2−c(n−2,2)−1条,然后除了 n − 1 n-1 n−1条边,还有 m − n + 1 m-n+1 m−n+1条边,然后根据插空法,可以得到最后答案为 ( n − 2 ) ! C ( n 2 − C ( n − 2 , 2 ) + m − n , m − n + 1 ) (n-2)!C(n^2-C(n-2,2)+m-n,m-n+1) (n−2)!C(n2−C(n−2,2)+m−n,m−n+1)
代码
#include <cstdio>
#define rr register
using namespace std;
typedef long long ll; ll ans=1;
const int mod=1000000007; int n,m;
inline ll ksm(ll x,int y){
rr ll ans=1;
for (;y;y>>=1,x=x*x%mod)
if (y&1) ans=ans*x%mod;
return ans;
}
signed main(){
scanf("%d%d",&n,&m);
rr int x=n*n-((n-2)*(n-1)>>1)+m-n;
for (rr int i=1;i<n-1;++i) ans=ans*i%mod;
for (rr int i=1;i<=m-n+1;++i)
ans=ans*(x-i+1)%mod*ksm(i,mod-2)%mod;
printf("%lld",ans);
return 0;
}
JZOJ 3059 回家 洛谷 3831 回家的路
题目
坐一站地铁需要两分钟,换乘需要一分钟,问回家的最短路径
分析
首先不可能把所有节点表示出来,只能把它们分成行和列,分别处理,对于行,处理同行的各个换乘口,对于列同理,这样跑一遍SPFA,就可以得到答案
代码
#include <cstdio>
#include <cctype>
#include <deque>
#include <cstring>
#include <algorithm>
#define rr register
using namespace std;
const int N=100100;
struct node{int y,w,next;}e[N<<2];
struct site{int x,y,rk;}t[N];
int k=1,n,m,ls[N<<1],dis[N<<1]; bool v[N<<1];
bool cmp1(site i,site j){return i.x<j.x||(i.x==j.x&&i.y<j.y);}
bool cmp2(site i,site j){return i.y<j.y||(i.y==j.y&&i.x<j.x);}
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void add(int x,int y,int w){
e[++k]=(node){y,w,ls[x]}; ls[x]=k;
e[++k]=(node){x,w,ls[y]}; ls[y]=k;
}
signed main(){
n=iut(); m=iut()+2;
for (rr int i=1;i<=m;++i) t[i]=(site){iut(),iut(),i}; sort(t+1,t+1+m,cmp2);
for (rr int i=1;i<m;++i) if (t[i+1].y==t[i].y) add(t[i].rk+m,t[i+1].rk+m,(t[i+1].x-t[i].x)<<1);
sort(t+1,t+1+m,cmp1); for (rr int i=1;i<=m;++i) add(i,i+m,i<m-1);
for (rr int i=1;i<m;++i) if (t[i+1].x==t[i].x) add(t[i].rk,t[i+1].rk,(t[i+1].y-t[i].y)<<1);
memset(dis,127/3,sizeof(dis)); dis[m-1]=0; v[m-1]=1;
rr deque<int>q; q.push_back(m-1);
while (q.size()){
rr int x=q.front(); q.pop_front();
for (rr int i=ls[x];i;i=e[i].next)
if (dis[e[i].y]>dis[x]+e[i].w){
dis[e[i].y]=dis[x]+e[i].w;
if (!v[e[i].y]){
v[e[i].y]=1;
if (q.size()&&dis[e[i].y]<dis[q.front()]) q.push_front(e[i].y);
else q.push_back(e[i].y);
}
}
v[x]=0;
}
if (dis[m]!=707406378) printf("%d",dis[m]); else printf("-1");
return 0;
}