【NOIP模拟】K进制+排队+航班

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_38083668/article/details/82938078

                                                     K进制

描述

给定一个K(2<=K<=16)进制数a,判断a是否能被K-1整除。

输入

第一行是一个整数t(1<=t<=50),表示测试点数量。

对于每组数据,第一行一个整数K,表示进制。

第二行一个K进制数,表示a。保证a是合法的K进制数,没有前导0,且只由’0’-‘9’、’A’-‘F’构成。

输出

如果a可以被K-1整除,输出”yes”,否则输出”no”。

样例输入

2
16
2D
10
19

样例输出

yes
no

提示

对于40%的数据,a的长度不超过5。

对于100%的数据,a的长度不超过100000。

解析:

       模拟。

代码:

#include <bits/stdc++.h>
using namespace std;

const int Max=100005;
int t,n,m,num[Max],sum;
char ch[Max];

inline int ksm(int a,int b,int mod)
{
	int ans=1;
	a%=mod;
	while(b)
	{
	  if(b&1) ans=(ans*a)%mod;
	  b>>=1;
	  a=(a*a)%mod;
	}
	return ans;
}

inline bool check()
{
	sum=0;
	for(int i=1;i<=n;i++)
	  if(ch[i]>='A') num[i]=(ch[i]-'A')+10;
	  else num[i]=ch[i]-'0';
	for(int i=1;i<=n;i++)
	  sum=(sum+num[i]*ksm(m,n-i,m-1))%(m-1);
	return !sum;
}

int main()
{
	scanf("%d\n",&t);
	while(t--)
	{
	  scanf("%d%s",&m,ch+1);
	  n=strlen(ch+1);
	  if(check()) printf("yes\n"); 
	  else printf("no\n");
	}
	return 0;
}

                                                         排队

描述

在成都某中学有m个男生与n个女生排队,这个学校的女生比较古怪,从某个位置(包含这个位置)开始往前数,男生的数量超过了女生的数量,女生会感觉不安全,于是会大叫起来,为了构建和谐校园,安排队伍时应该避免这样的情况。请你计算出不会引发尖叫的排队方案的概率。(排队方案不同定义:当且仅当某个某个位置人不一样,如男生A、男生B ,与男生B、男生A ,2个排列是不同方案)

输入

第一行1个整数, 表示测试数据的组数。

每个数据 有两个数 N,M(N个女生,M个男生)

输出

对于每组数据,输出一个实数(保留到小数点后 6 位)

样例输入

3
1 0
0 1
1 1

样例输出

1.000000
0.000000
0.500000

提示

【 Hint】

第一组:只有一个女生,一种方案且可行

第二组:只有1个男生,一种方案且不行

第三组:两种方案 女、男可行,男、女不可行,可行概率0.5

【数据规模】

30%的数据: (测试组数<=10),(0<=N,M<=1000).

100%的数据: (测试组数=9008 ), ( 0<=N,M<=20000 ).

解析:
       可以将原问题转化一下,看成是在一个二维平面上行走,女生看向右移动,男生看成向上移动,那么到达(N,M)点且路线又不走到y=x这条直线上方的路线总数就是答案,这个组合问题很经典,方案数为C(M+N,M)-(M+N,M-1),所以可以知道答案就是1-M/(N+1) 。(注意本来因为男生和女生中两两不同要乘n!m!但是可以约掉)。

代码:

#include <bits/stdc++.h>
using namespace std;

int t;
double n,m;

int main()
{
	scanf("%d",&t);
	while(t--)
	{
	  scanf("%lf%lf",&n,&m);
	  if(n<m) printf("%.6f\n",0);
	  else printf("%.6f\n",1-(m/(n+1)));
	}
	return 0;
}

                                                        航班

描述

L因为业务繁忙,经常会到处出差。因为他是航空公司的优质客户,于是某个航空公司给了他一个优惠券。

他可以利用这个优惠券在任何一个国家内的任意城市间免费旅行,当他的路线跨国才会产生费用。L有一个航空公司的价格表与航线。而且每个城市出发都能到所有的城市,2个城市间可能有不止一个航班,一个国家内的2个城市间一定有不同的路线,但是不同国家的城市间只有一条路线。L想知道从每个城市出发到产生费用最多的城市,不过你不能重复在一个航班上飞来飞去产生费用,必须沿最少的费用路线飞行

输入

第一行,两个整数 N,M,表示N 个城市, M 条航线。

接下来 M 行,每行三个整数 a,b,c,表示城市 a,b 之间有一条费用为 c 的航线。

输出

共 N 行,第 i 行为从城市 i 出发到达每个城市额外费用的最大值。

样例输入

6 6
1 4 2
1 2 6
2 5 3
2 3 7
6 3 4
3 1 8

样例输出

4
4
4
6
7
7

提示

【解释】

有四个国家,包含的城市分别为 {1,2,3},{4},{5},{6}。

从城市 1 出发到达城市 6,乘坐(1,3)(3,6)两个航班费用最大,(1,3)在国内为免费航班, (3,6)的费用为 4,所以从 1 出发的最大费用为 4。

【数据规模】

对于 40%的数据 1<=N<=1000,1<=M<=1000

对于 100%的数据 1<=N<=20000,1<=M<=200000

解析:

       边-双联通缩点+树形DP。

代码:

#include <bits/stdc++.h>
using namespace std;

const int Max=200100;
int n,m,Index,cnt,tot,size=1;
int num[Max],low[Max],father[Max],p[Max],vis[Max];
int first[Max],f[Max][3],First[Max],ans[Max],son[Max];
struct shu{int to,next,len;};
shu edge[Max<<1],Edge[Max<<1];

inline int get_int()
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') f=-1,c=getchar();
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}
inline void print(int x)
{
	if(x<0) x=-x,putchar('-');
	if(x>9) print(x/10);
	putchar('0'+x%10);
}

inline void build(int x,int y,int z)
{
	edge[++size].next=first[x];
	first[x]=size;
	edge[size].to=y,edge[size].len=z;
}

inline void Build(int x,int y,int z)
{
	Edge[++size].next=First[x];
	First[x]=size;
	Edge[size].to=y,Edge[size].len=z;
}

inline void tarjan(int point,int v)
{
	num[point]=low[point]=++Index;
	p[++tot]=point;
	for(int u=first[point];u;u=edge[u].next)
	{
	  int to=edge[u].to;
	  if((u^1)==v) continue;
	  if(!num[to]) tarjan(to,u),low[point]=min(low[point],low[to]);
	  else low[point]=min(low[point],num[to]);
	}
	if(low[point]==num[point])
	{
	  cnt++;
	  while(1)
	  {
	  	int x=p[tot--];
	  	father[x]=cnt;
	  	if(x==point) break;
	  }
	}
}

inline void rebuild()
{
	size=0;
	for(int i=1;i<=n;i++)
	  for(int u=first[i];u;u=edge[u].next)
	    if(father[i]!=father[edge[u].to]) Build(father[i],father[edge[u].to],edge[u].len);
}

inline void dfs1(int point)
{
	vis[point]=1;
	for(int u=First[point];u;u=Edge[u].next)
	{
	  int to=Edge[u].to;
	  if(vis[to]) continue;
	  dfs1(to);
	  if(f[to][0]+Edge[u].len>f[point][0])
	    son[point]=to,f[point][1]=f[point][0],f[point][0]=f[to][0]+Edge[u].len;
	  else f[point][1]=max(f[point][1],f[to][0]+Edge[u].len);
	}
}

inline void dfs2(int point)
{
	vis[point]=1;
	for(int u=First[point];u;u=Edge[u].next)
	{
	  int to=Edge[u].to;
	  if(vis[to]) continue;
	  if(to==son[point]) f[to][2]=max(f[point][2],f[point][1])+Edge[u].len;
	  else f[to][2]=max(f[point][2],f[point][0])+Edge[u].len;
	  dfs2(to);
	}
}

inline int mx(int x,int y){return x<y?y:x;}

int main()
{
	n=get_int(),m=get_int();
	for(int i=1;i<=m;i++)
	{
	   int x=get_int(),y=get_int(),z=get_int();
	   build(x,y,z),build(y,x,z);
	}
	for(int i=1;i<=n;i++) if(!num[i]) tarjan(i,0);
	rebuild();
	dfs1(1);
	memset(vis,0,sizeof(vis));
	dfs2(1);
	for(int i=1;i<=cnt;i++) ans[i]=mx(f[i][0],f[i][2]);
	for(int i=1;i<=n;i++) print(ans[father[i]]),putchar('\n');
	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_38083668/article/details/82938078