较为基础的比赛,但ak了还是很开心.
m(1000)种石子,每种无限个,从这些石子中取出n(1000)个,并按顺序排列起来,为了好看,相邻的石子不能相同。有多少种排列的方法,结果模1e9+7.
第一个石子有m种取法,第2~n个的限制是不能与前一个相同,有m-1种取法.
答案是 m∗(m−1)n−1mod1000000007 m ∗ ( m − 1 ) n − 1 mod 1000000007
复杂度O(n),可以用快速幂优化.
int main(void)
{
ll n=read()-1, m=read();
ll ans = m;
while(n--)
ans = ans * (m-1) % MOD;
cout << ans <return 0;
}
给定一棵树,每个节点上有一只鸟,每秒钟每只鸟都可以从一个节点移动到相邻节点上,但每秒钟每条边只能承载一只鸟的飞行.问所有鸟移动到根节点(1号节点)所花的时间.
假设根节点只有一个孩子,那么答案就是总结点个数-1,也即这个以这个孩子为根的子树的节点个数,原因是这个子树与根节点只有一条边相连,每秒钟最多走一个,且每秒钟都可以走一个,因为每秒钟总会有至少一只鸟在子树的根处等待.
假设根节点有若干个孩子,可以发现以这些孩子为根的子树之间是互不影响的,所以答案就是以根节点的孩子为根的子树中最多的节点数目.
复杂度O(n)
vector<int> save[M];
int getnode(int n, int fa)
{
int ret = 1;
for(auto x : save[n])
if(x != fa)
ret += getnode(x, n);
return ret;
}
int main(void)
{
int n = read();
for(int i = 1; i < n; i++)
{
int a = read(), b = read();
save[a].push_back(b);
save[b].push_back(a);
}
int ans = 0;
for(auto x : save[1])
ans = max(ans, getnode(x, 1));
printf("%d\n", ans );
return 0;
}
有一个长为n(1e6)的RB串,m(1e6)次询问,每次问第q个R或B字符出现在串中的第几个位置.
预先统计出所有的答案,对每个问题直接输出.复杂度O(n+m)
int rs[M], bs[M];
char tic[M];
int main(void)
{
int n = read(), m = read();
scanf("%s", tic);
int rn = 0, bn = 0;
for(int i = 0; tic[i]; i++)
if(tic[i] == 'R')
rs[++rn] = i + 1;
else
bs[++bn] = i + 1;
char op[3];
int t;
while(m--)
{
scanf("%s %d", op, &t);
if(op[0] == 'R')
printf("%d\n", t <= rn ? rs[t] : -1 );
else
printf("%d\n", t <= bn ? bs[t] : -1 );
}
return 0;
}
一个n个节点的树,给出除根节点外所有节点的父亲及与父亲相连的边长,问所有节点距离根节点最远能有多远?
记忆化搜索一下,注意根节点不一定是1号点.复杂度O(n)
struct node
{
int len;
int all = -1;
int fa = -1;
} save[M];
int getall(int id)
{
return save[id].all == -1
? save[id].all = save[id].len + getall(save[id].fa)
: save[id].all;
}
int main(void)
{
int n = read();
for(int i = 1; i < n; i++)
{
int id = read(), fa = read(), len = read();
save[id].fa = fa;
save[id].len = len;
}
for(int i = 1; i <= n; i++)
if(save[i].fa == -1)
save[i].all = 0;
int ans = 0;
for(int i = 1; i <= n; i++)
{
if(save[i].all == -1)
getall(i);
ans = max(ans, save[i].all);
}
printf("%d\n", ans );
return 0;
}
有一条路,路上有很多两个点之间的单向隧道,在每一个点可以选择:朝前走一个点,朝后走一个点,进入一个隧道(如果当前点有)并从隧道另一边出来,每个选择都花费一秒时间.问至少需要多少时间可以从起点走到终点.
bfs,用dis[i]是否为-1来表示是否访问过这个点.
因为一定能到达终点,每次循环时观察dis[m]是否为-1作为判断条件.
数据范围较小,每次直接遍历所有隧道,复杂度O(nm)
int dis[M];
pair<int, int> trap[M];
int main(void)
{
int m = read(), n = read();
memset(dis, -1, sizeof(dis));
dis[0] = 0, dis[1] = 1;
for(int i = 0; i < n; i++)
{
trap[i].first = read();
trap[i].second = read();
}
queue<int> q;
q.push(1);
while(dis[m] == -1)
{
int now = q.front();
q.pop();
for(int i = 0; i < n; i++)
{
if(trap[i].first == now && dis[trap[i].second] == -1)
{
dis[trap[i].second] = dis[now] + 1;
q.push(trap[i].second);
}
}
if(dis[now - 1] == -1)
{
dis[now - 1] = dis[now] + 1;
q.push(now - 1);
}
if(dis[now + 1] == -1)
{
dis[now + 1] = dis[now] + 1;
q.push(now + 1);
}
}
printf("%d\n", dis[m] );
return 0;
}
有n(50000)种商品,每种都有一个体积vi(50000),每种个数无限,给定一个m(50000),问组成1~m体积的方法总数.
遇事不决写暴力
完全背包求方案数,复杂度O(nm),牛客的评测机是真的好
int save[M], dp[M];
int main(void)
{
int n = read(), m = read();
for(int i = 1; i <= n; i++)
save[i] = read();
dp[0] = 1;
for(int i = 1; i <= n; i++)
for(int j = save[i]; j <= m; j++)
dp[j] = (dp[j - save[i]] + dp[j]) % MOD;
int ans = 0;
for(int i = 1; i <= m; i++)
ans = (ans + dp[i]) % MOD;
printf("%d\n", ans );
return 0;
}