T1: K进制
kbased.cpp
【题意】
给定一个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<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
void in(int &x)
{
int f=1;x=0;char w=getchar();
while(w<'0'||w>'9') {if(w=='-') f=-f;w=getchar();}
while(w>='0'&&w<='9') {x=10*x+w-'0';w=getchar();}
x*=f;
}
int main()
{
int t;in(t);char a[100400];long long s[100400];
while(t--)
{
memset(s,0,sizeof(s));
int k;in(k);
scanf("%s",a);
int len=strlen(a);
s[len-1]=1;
long long ans=0,shu;
for(int i=len-1;i>=0;i--)
{
if(i!=len-1) s[i]=(s[i+1]*1ll*k)%(k-1);
shu=a[i]-'0';
if(a[i]=='A') shu=10;if(a[i]=='B') shu=11;
if(a[i]=='C') shu=12;if(a[i]=='D') shu=13;
if(a[i]=='E') shu=14;if(a[i]=='F') shu=15;
ans+=(shu*s[i])%(k-1);
}
if(ans%(k-1)==0) printf("yes\n");
else printf("no\n");
}
return 0;
}
T2: 排队
fseq.cpp
【题意】
在成都某中学有 m 个男生与 n 个女生排队,这个学校的女生比较古怪,从某个位
置(包含这个位置)开始往前数,男生的数量超过了女生的数量,女生会感觉不安全,于
是会大叫起来,为了构建和谐校园,安排队伍时应该避免这样的情况。请你计算出不会引
发尖叫的排队方案的概率。(排队方案不同定义:当且仅当某个某个位置人不一样,如男
生A、男生B ,与男生B、男生A ,2个排列是不同方案)
【 Input】
第一行1个整数, 表示测试数据的组数。
每个数据 有两个数 N,M(N个女生,M个男生)
【 Output】
对于每组数据,输出一个实数(保留到小数点后 6 位)
【 Sample Input】
3
1 0
0 1
1 1
【 Sample Output】
1.000000
0.000000
0.500000
【 Hint】
第一组:只有一个女生,一种方案且可行
第二组:只有1个男生,一种方案且不行
第三组:两种方案 女、男可行,男、女不可行,可行概率 0.5
【数据规模】
30%的数据: (测试组数<=10),(0<=N,M<=1000).
100%的数据: (测试组数=9008 ), ( 0<=N,M<=20000 ).
分析:组合数学
原题地址:https://www.lydsy.com/JudgeOnline/problem.php?id=1856
我们把排列映射到二维平面上
是男生就向上走一步
是女生就向右走一步
当路径始终在直线y=x下方时这个情况就合法
用组合数学推算出方案数即为C(M+N,M)-(M+N,M-1)
答案就是1-M/(N+1)
代码略
T3: 航班
prize.cpp
【描述】
L因为业务繁忙,经常会到处出差。因为他是航空公司的优质客户,于是某个航空
公司给了他一个优惠券。
他可以利用这个优惠券在任何一个国家内的任意城市间免费旅行,当他的路线跨国
才会产生费用。L有一个航空公司的价格表与航线。而且每个城市出发都能到所有的城
市,2个城市间可能有不止一个航班,一个国家内的 2个城市间一定有不同的路线,但是
不同国家的城市间只有一条路线。L想知道从每个城市出发到产生费用最多的城市,不过
你不能重复在一个航班上飞来飞去产生费用,不行沿最少的费用路线飞行。
【 输入】
第一行,两个整数 N,M,表示N 个城市, M 条航线。
接下来 M 行,每行三个整数 a,b,c,表示城市 a,b 之间有一条费用为 c 的航
线。
【 输出】
共 N 行,第 i 行为从城市 i 出发到达每个城市额外费用的最大值。
【 Sample Input】
6 6
1 4 2
1 2 6 2 5 3
2 3 7
6 3 4
3 1 8
【 Sample Output】
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
分析:先用SCC缩点,然后用两次dfs求树的直径:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=4200;
int nxt[N],d[N],tot=0,head[N],vis[N],n,x,y,m;
void add(int x,int y)
{
vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;
}
void dfs(int v)
{
for(int i=head[v];i;i=nxt[i])
if(!d[vis[i]])
{
d[vis[i]]=d[v]+1;
dfs(vis[i]);
}
}
int main()
{
cin>>n;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1);
for(int i=m=1;i<=n;i++) if(d[i]>d[m]) m=i;
memset(d,0,sizeof(d));
dfs(m);
for(int i=m=1;i<=n;i++) if(d[i]>d[m]) m=i;
printf("%d",d[m]);
return 0;
}
推论:一个点到另一个点的最长路的终点一定是树的直径的两端:
证明:
若树的直径端点为A,B 且存在点C 到点D的距离大于点C到点A或点B的距离
此时A->D 或 B->D 会成为新的直径,可以画图理解一下
代码:
#include<bits/stdc++.h>
#define maxn 20005
#define maxm 200005
using namespace std;
int n,m,id,dfn[maxn],low[maxn],head[maxn],head2[maxn],cnt;
int dis[maxn],dis1[maxn],mx=0,root;
int belong[maxn],belnum;
bool vis[maxn];
stack<int> stk;
struct Edge{
int u,v,val,next;
}edge[maxm<<1],e[maxm<<1];
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
namespace Tarjan{
inline void add(int u,int v,int val)
{
edge[++cnt].v=v;
edge[cnt].u=u;
edge[cnt].val=val;
edge[cnt].next=head[u];
head[u]=cnt;
}
inline void tarjan(int u,int fa)
{
dfn[u]=low[u]=++id;
vis[u]=1;
stk.push(u);
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(!dfn[v])
{
tarjan(v,u);
low[u]=min(low[u],low[v]);
}
else if(vis[v]&&v!=fa)
{
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u])
{
belnum++;
int temp;
do{
temp=stk.top();
belong[temp]=belnum;
vis[temp]=0;
stk.pop();
}while(temp!=u);
}
}
inline void solve1(){
memset(head,-1,sizeof(head));
for(int i=1,u,v,val;i<=m;i++){
u=read();v=read();val=read();
add(u,v,val);add(v,u,val);
}
for(int i=1;i<=n;i++){
if(!dfn[i]) tarjan(i,0);
}
}
}
namespace LP{
inline void Add(int u,int v,int val){
e[++cnt].v=v;
e[cnt].val=val;
e[cnt].next=head2[u];
head2[u]=cnt;
}
void dfs1(int u,int fa){
for(int i=head2[u];i!=-1;i=e[i].next)
{
int v=e[i].v;
if(v==fa) continue;
dis[v]=dis[u]+e[i].val;
if(dis[v]>mx) mx=dis[v],root=v;
dfs1(v,u);
}
}
void dfs2(int u,int fa){
for(int i=head2[u];i!=-1;i=e[i].next)
{
int v=e[i].v;
if(v==fa) continue;
dis1[v]=dis1[u]+e[i].val;
dfs2(v,u);
}
}
inline void solve2(){
cnt=0;
memset(head2,-1,sizeof(head2));
for(int i=1;i<=n;i++)
for(int j=head[i];j!=-1;j=edge[j].next)
{
if(belong[i]!=belong[edge[j].v])
Add(belong[i],belong[edge[j].v],edge[j].val);
}
dfs1(1,-1);
mx=0;memset(dis,0,sizeof(dis));
dfs1(root,-1);
mx=0;
dfs2(root,-1);
for(int i=1;i<=n;i++)
printf("%d\n",max(dis[belong[i]],dis1[belong[i]]));
}
}
int main(){
n=read();m=read();
Tarjan::solve1();
LP::solve2();
return 0;
}