2019.01.23【NOIP提高组】模拟 A & B 组

111 篇文章 0 订阅
58 篇文章 0 订阅

JZOJ 3084 超级变变变

题目

定义 f [ n ] = f[n]= f[n]=

  • n n n是奇数, f [ n ] = n − 1 f[n]=n-1 f[n]=n1
  • 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] [ab]有多少个可以变成 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 2n1的点是可以任意排列的,所以答案要乘 ( n − 2 ) ! (n-2)! (n2)!,然后、如果求出了最短路,那么如果出现了捷径边,肯定是不可行的,那么这样的边有 C ( n − 2 , 2 ) C(n-2,2) C(n2,2)条,那么可选的边数就是 n 2 − c ( n − 2 , 2 ) − 1 n^2-c(n-2,2)-1 n2c(n2,2)1条,然后除了 n − 1 n-1 n1条边,还有 m − n + 1 m-n+1 mn+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) (n2)!C(n2C(n2,2)+mn,mn+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; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值