1315 问题 AS: 网格VI
时间限制: 1.000 Sec 内存限制: 128 MB
提交 状态
题目描述
某城市的街道呈网格状,左下角坐标为A(0, 0),右上角坐标为B(n, m),其中n >= m。现在从A(0, 0)点出发,只能沿着街道向正右方或者正上方行走,且不能经过图示中直线左上方的点,即任何途径的点(x, y)都要满足x >= y,请问在这些前提下,到达B(n, m)有多少种走法。
输入
仅有一行,包含两个整数n和m,表示城市街区的规模。
输出
仅有一个整数和一个换行/回车符,表示不同的方案总数。
样例输入 Copy
6 6
样例输出 Copy
132
提示
100%的数据中,1 <= m <= n <= 5 000
#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int a[N],b[N];
int p[N],cnt;
bool st[N];
void init(int n)
{
for(int i=2;i<=n;i++){
if(!st[i])p[cnt++]=i;
for(int j=0;p[j]*i<=n;j++){
st[p[j]*i]=true;
if(i%p[j]==0)break;
}
}
}
int get(int n,int p)
{
int s=0;
while(n)s+=n/p,n/=p;
return s;
}
void mul(int r[],int& len,int x)
{
int t=0;
for(int i=0;i<len;i++){
t+=r[i]*x;
r[i]=t%10;
t/=10;
}
while(t){
r[len++]=t%10;
t/=10;
}
}
void sub(int a[],int al,int b[],int bl)
{
for(int i=0,t=0;i<al;i++){
a[i]-=t+b[i];
if(a[i]<0)a[i]+=10,t=1;
else t=0;
}
}
int C(int x,int y,int r[N])
{
int len=1;
r[0]=1;
for(int i=0;i<cnt;i++){
int s=get(x,p[i])-get(y,p[i])-get(x-y,p[i]);
while(s--)mul(r,len,p[i]);
}
return len;
}
int main()
{
init(N-1);
int n,m;
cin>>n>>m;
int al=C(n+m,m,a);
int bl=C(n+m,n+1,b);
sub(a,al,b,bl);
int k=al-1;
while(!a[k]&&k>0)k--;
while(k>=0)cout<<a[k--];
return 0;
}
1316 问题 AT: 有趣的数列
时间限制: 1.000 Sec 内存限制: 128 MB
提交 状态
题目描述
我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件:
(1)它是从1到2n共2n个整数的一个排列{ai};
(2)所有的奇数项满足a1<a3<…<a2n-1,所有的偶数项满足a2<a4<…<a2n;
(3)任意相邻的两项a2i-1与a2i(1≤i≤n)满足奇数项小于偶数项,即:a2i-1<a2i。
现在的任务是:对于给定的n,请求出有多少个不同的长度为2n的有趣的数列。因为最后的答案可能很大,所以只要求输出答案 mod P的值。
输入
只包含用空格隔开的两个整数n和P。输入数据保证,50%的数据满足n≤1000,100%的数据满足n≤1000000且P≤1000000000。
输出
仅含一个整数,表示不同的长度为2n的有趣的数列个数mod P的值。
样例输入 Copy
3 10
样例输出 Copy
5
提示
对应的5个有趣的数列分别为(1,2,3,4,5,6),(1,2,3,5,4,6),(1,3,2,4,5,6),(1,3,2,5,4,6),(1,4,2,5,3,6)。
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef unsigned long long LL;
typedef pair<int,int>PII;
const int N=2000010;
int p[N],cnt;
bool st[N];
int n,m;
void init(int n)
{
for(int i=2;i<=n;i++){
if(!st[i])p[cnt++]=i;
for(int j=0;p[j]*i<=n;j++){
st[p[j]*i]=true;
if(i%p[j]==0)break;
}
}
}
int qmi(int a,int k)
{
int res=1;
while(k)
{
if(k&1)res=(LL)res*a%m;
a=(LL)a*a%m;
k>>=1;
}
return res;
}
int get(int n,int p)
{
int s=0;
while(n){
s+=n/p;
n/=p;
}
return s;
}
int c(int a,int b)
{
int res=1;
for(int i=0;i<cnt;i++){
int pr=p[i];
int s=get(a,pr)-get(b,pr)-get(a-b,pr);
res=(LL)res*qmi(pr,s)%m;
}
return res;
}
void solve()
{
cin>>n>>m;
init(n*2);
//cout<<cnt;
//return 0;
cout<<(c(n*2,n)-c(n*2,n-1)+m)%m;
}
int main()
{
int t=1;
//cin>>t;
while(t--)
{
solve();
}
return 0;
}
1172 祖孙询问
给定一棵包含 n 个节点的有根无向树,节点编号互不相同,但不一定是 1∼n。
有 m 个询问,每个询问给出了一对节点的编号 x 和 y,询问 x 与 y 的祖孙关系。
输入格式
输入第一行包括一个整数 表示节点个数;
接下来 n 行每行一对整数 a 和 b,表示 a 和 b 之间有一条无向边。如果 b 是 −1,那么 a 就是树的根;
第 n+2 行是一个整数 m 表示询问个数;
接下来 m 行,每行两个不同的正整数 x 和 y,表示一个询问。
输出格式
对于每一个询问,若 x 是 y 的祖先则输出 1,若 y 是 x 的祖先则输出 2,否则输出 0。
数据范围
1≤n,m≤4×104
1≤每个节点的编号≤4×104
输入样例:
10
234 -1
12 234
13 234
14 234
15 234
16 234
17 234
18 234
19 234
233 19
5
234 233
233 12
233 13
233 15
233 19
输出样例:
1
0
0
0
2
#include <bits/stdc++.h>
#define x first
#define y second
#define endl "\n"
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 100010, mod = 1e6 + 7;
int f[N][16];
int d[N];
int e[N], ne[N], h[N], idx;
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void bfs(int u)
{
memset(d, 0x3f, sizeof d);
queue<int> q;
q.push(u);
d[u] = 1;
d[0] = 0;
while (q.size())
{
auto t = q.front();
q.pop();
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if (d[j] > d[t] + 1)
{
d[j] = d[t] + 1;
q.push(j);
f[j][0] = t;
for (int k = 1; k <= 15; k++)
{
f[j][k] = f[f[j][k - 1]][k - 1];
}
}
}
}
}
int lca(int a, int b)
{
if (d[a] < d[b])
swap(a, b);
for (int k = 15; k >= 0; k--)
{
if (d[f[a][k]] >= d[b])
a = f[a][k];
}
if (a == b)
return a;
for (int k = 15; k >= 0; k--)
{
if (f[a][k] != f[b][k])
{
a = f[a][k];
b = f[b][k];
}
}
return f[a][0];
}
void solve()
{
int n;
int root;
cin >> n;
memset(h, -1, sizeof h);
for (int i = 0; i < n; i++)
{
int a, b;
cin >> a >> b;
if (b == -1)
root = a;
else
add(a, b), add(b, a);
}
bfs(root);
int m;
cin >> m;
while (m--)
{
int a, b;
cin >> a >> b;
int p = lca(a, b);
if (p == a)
puts("1");
else if (p == b)
puts("2");
else
puts("0");
}
}
int main()
{
int t = 1;
// scanf("%d", &t);
while (t--)
{
solve();
}
return 0;
}
1171 距离
给出 n 个点的一棵树,多次询问两点之间的最短距离。
注意:
- 边是无向的。
- 所有节点的编号是 1,2,…,n
输入格式
第一行为两个整数 n 和 m。n 表示点数,m 表示询问次数;
下来 n−1 行,每行三个整数 x,y,k,表示点 x 和点 y 之间存在一条边长度为 k;
再接下来 m 行,每行两个整数 x,y,表示询问点 x 到点 y 的最短距离。
树中结点编号从 1 到 n。
输出格式
共 m 行,对于每次询问,输出一行询问结果。
数据范围
2≤n≤104
1≤m≤2×104
0<k≤100
1≤x,y≤n
输入样例1:
2 2
1 2 100
1 2
2 1
输出样例1:
100
100
输入样例2:
3 2
1 2 10
3 1 15
1 2
3 2
输出样例2:
10
25
#include<bits/stdc++.h>
#define x first
#define t second
using namespace std;
typedef pair<int,int>PII;
const int N=40010;
int n,m;
int h[N],ne[N],e[N],w[N],idx;
int d[N];
int p[N],res[N],st[N];
vector<PII>g[N];
void add(int a,int b,int c)
{
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
void dfs(int u,int fa)
{
for(int i=h[u];i!=-1;i=ne[i]){
int j=e[i];
if(j==fa)continue;
d[j]=d[u]+w[i];
dfs(j,u);
}
}
int find(int x)
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
void tar(int u)
{
st[u]=1;
for(int i=h[u];i!=-1;i=ne[i]){
int j=e[i];
if(!st[j]){
tar(j);
p[j]=u;
}
}
for(auto [x,y]:g[u]){
if(st[x]==2){
int h=find(x);
res[y]=d[u]+d[x]-2*d[h];
}
}
st[u]=2;
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=1;i<n;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c),add(b,a,c);
}
for(int i=0;i<m;i++){
int a,b;
cin>>a>>b;
if(a!=b){
g[a].push_back({b,i});
g[b].push_back({a,i});
}
}
for(int i=1;i<=n;i++)p[i]=i;
dfs(1,-1);
tar(1);
for(int i=0;i<m;i++)cout<<res[i]<<endl;
return 0;
}
1185 单词游戏
有 N 个盘子,每个盘子上写着一个仅由小写字母组成的英文单词。
你需要给这些盘子安排一个合适的顺序,使得相邻两个盘子中,前一个盘子上单词的末字母等于后一个盘子上单词的首字母。
请你编写一个程序,判断是否能达到这一要求。
输入格式
第一行包含整数 T,表示共有 T 组测试数据。
每组数据第一行包含整数 N,表示盘子数量。
接下来 N 行,每行包含一个小写字母字符串,表示一个盘子上的单词。
一个单词可能出现多次。
输出格式
如果存在合法解,则输出”Ordering is possible.”,否则输出”The door cannot be opened.”。
数据范围
1≤N≤105,
单词长度均不超过1000
输入样例:
3
2
acm
ibm
3
acm
malform
mouse
2
ok
ok
输出样例:
The door cannot be opened.
Ordering is possible.
The door cannot be opened.
#include<bits/stdc++.h>
using namespace std;
int din[30],dout[30];
int p[30];
bool st[30];
int find(int x)
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
int main()
{
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=0;i<26;i++)p[i]=i;
memset(din,0,sizeof din);
memset(dout,0,sizeof dout);
memset(st,0,sizeof st);
for(int i=0;i<n;i++){
string s;
cin>>s;
int a=s[0]-'a',b=s.back()-'a';
st[a]=st[b]=true;
din[b]++,dout[a]++;
a=find(a),b=find(b);
p[a]=b;
}
int c1=0,c2=0;
bool f=true;
for(int i=0;i<26;i++){
if(din[i]!=dout[i]){
if(din[i]+1==dout[i])c1++;
else if(din[i]==dout[i]+1)c2++;
else{
f=false;
break;
}
}
}
if(st&&!(!c1&&!c2||c1==1&&c2==1))f=false;
int s=-1;
for(int i=0;i<26;i++){
if(st[i]){
if(s==-1)s=find(i);
else if(s!=find(i)){
f=false;
break;
}
}
}
if(f)puts("Ordering is possible.");
else puts("The door cannot be opened.");
}
}