题目链接
01:http://acm.hdu.edu.cn/showproblem.php?pid=6114
02:http://acm.hdu.edu.cn/showproblem.php?pid=6115
03:http://acm.hdu.edu.cn/showproblem.php?pid=6116
04:http://acm.hdu.edu.cn/showproblem.php?pid=6117
05:http://acm.hdu.edu.cn/showproblem.php?pid=6118
06:http://acm.hdu.edu.cn/showproblem.php?pid=6119
一些题解
01 Chess
题意说是要找在n*m的棋盘上最多的车让他们互相不攻击,并且下一行的车要在上一行的车的右边,问摆放的方案数。
那么一共就有min(n, m)个车,一共有max(n, m)个位置则答案就是Cmax(n, m)min(n, m)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL maxn(1000005), mod(1e9 + 7);
LL Jc[maxn];
void calJc() //求maxn以内的数的阶乘
{
Jc[0] = Jc[1] = 1;
for(LL i = 2; i < maxn; i++)
Jc[i] = Jc[i - 1] * i % mod;
}
/*
//拓展欧几里得算法求逆元
void exgcd(LL a, LL b, LL &x, LL &y) //拓展欧几里得算法
{
if(!b) x = 1, y = 0;
else
{
exgcd(b, a % b, y, x);
y -= x * (a / b);
}
}
LL niYuan(LL a, LL b) //求a对b取模的逆元
{
LL x, y;
exgcd(a, b, x, y);
return (x + b) % b;
}
*/
//费马小定理求逆元
LL pow(LL a, LL n, LL p) //快速幂 a^n % p
{
LL ans = 1;
while(n)
{
if(n & 1) ans = ans * a % p;
a = a * a % p;
n >>= 1;
}
return ans;
}
LL niYuan(LL a, LL b) //费马小定理求逆元
{
return pow(a, b - 2, b);
}
LL C(LL a, LL b) //计算C(a, b)
{
return Jc[a] * niYuan(Jc[b], mod) % mod
* niYuan(Jc[a - b], mod) % mod;
}
int main()
{
int t;
scanf("%d", &t);
int n, m;
calJc();
while(t--)
{
scanf("%d%d", &n, &m);
printf("%d\n", C(max(n, m),min(n, m)));
}
return 0;
}
06 小小粉丝度度熊
题意很简单,给定n个区间,每个区间有L-R已经被覆盖,给定m个填充剂每一个可以覆盖一个数,问最能连续覆盖多少个数。
直接合并连续或相交的区间再根据区间开始的数由大到小排序。然后跑一遍记录当前消耗和当前连续数,当消耗的填充剂大于m就把当前首部区间去掉。然后每次比较最大值就可以了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define rep(i, s, t) for(int i = s;i <= t;i++)
#define rap(i, s, t) for(int i = s;i >= t;i--)
using namespace std;
struct Node
{
long long st, en;
}node[100004];
struct Bag
{
long long st, en;
}beg[100004];
long long n, m;
int cmp(Node a, Node b)
{
return a.st < b.st;
}
int main()
{
while(scanf("%I64d%I64d", &n, &m) != EOF)
{
rep(i, 1, n)
scanf("%I64d%I64d", &node[i].st, &node[i].en);
sort(node + 1, node + 1 + n, cmp);
int cnt = 0;
int xen = 0;
rep(i, 1, n){
if(node[i].st <= xen&&i != 1){
if(node[i].en <= xen)
continue;
else
{
beg[cnt].en = node[i].en;
xen = node[i].en;
}
}
else
{
beg[++cnt].en = node[i].en;
xen = node[i].en;
beg[cnt].st = node[i].st;
}
}
long long xh = 0;
long long ans = 0;
int beginn = 1;
for(int i = 1;i <= cnt;i++){
if(i != 1){
int lsxh = beg[i].st - beg[i - 1].en - 1;
xh += lsxh;
}
while(xh > m)
{
xh -= beg[beginn + 1].st - beg[beginn].en - 1;
beginn++;
}
ans = max(ans, beg[i].en - beg[beginn].st + 1 + m - xh);
}
printf("%I64d\n", ans);
}
return 0;
}
补题
02 Factory
暴力加LCA把所有配对全部加入查询,然后标记问题序号,注意这里不能用公共祖先数组作为距离树根变去除,因为有可能这两个点相同且没有后继即ancestor数组不会更新,那么只有在并查集合并的时候把子树的标记用父数代替,不能像以前这样随意了233333.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#define rep(i, s, t) for(int i = s;i <= t;i++)
#define rap(i, s, t) for(int i = s;i >= t;i--)
#define inf 0x3f3f3f3f
using namespace std;
int n, m;
const int M = 100004;
vector<int>tree[M];
vector<int>query[M];
vector<int>queid[M];
vector<int>worth[M];
vector<int>G[M];
bool vis[M];
int f[M];
//int ancestor[M];
int dis[M];
int ans[M];
int Q;
int findd(int x)
{
return x == f[x]?f[x]:f[x] = findd(f[x]);
}
void uni(int x, int y)
{
x = findd(x);
y = findd(y);
if(x != y)
f[y] = x;
}
void init()
{
rep(i, 0, n){
G[i].clear();
vis[i] = false;
tree[i].clear();
query[i].clear();
worth[i].clear();
queid[i].clear();
f[i] = i;
dis[i] = 0;
ans[i] = inf;
}
}
void input_tree()
{
rep(i, 1, n - 1){
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
tree[a].push_back(b);
worth[a].push_back(c);
tree[b].push_back(a);
worth[b].push_back(c);
}
}
void input_query()
{
scanf("%d", &Q);
rep(i, 1, Q)
{
int a, b;
scanf("%d%d", &a, &b);
rep(j, 0, (int)G[a].size() - 1)
{
rep(k, 0, (int)G[b].size() - 1)
{
query[G[a][j]].push_back(G[b][k]);
queid[G[a][j]].push_back(i);
query[G[b][k]].push_back(G[a][j]);
queid[G[b][k]].push_back(i);
}
}
}
}
void tarjan(int x, int value)
{
dis[x] = value;
vis[x] = true;
rep(i, 0, (int)tree[x].size() - 1){
int v = tree[x][i];
if(vis[v] == true)
continue;
tarjan(v, value + worth[x][i]);
uni(x, v);
//ancestor[findd(x)] = x;
}
rep(i, 0, (int)query[x].size() - 1){
int v = query[x][i];
if(vis[v]&&ans[queid[x][i]] > dis[x] + dis[v] - 2 * dis[findd(v)])
ans[queid[x][i]] = dis[x] + dis[v] - 2 * dis[findd(v)];
//printf("%d %d %d %d %d %d %d %d\n", x, v, findd(v), dis[x], dis[v], dis[findd(v)], queid[x][i], ans[queid[x][i]]);
}
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &n, &m);
init();
input_tree();
rep(i, 1, m){
int a;
scanf("%d", &a);
rep(j, 1, a){
int b;
scanf("%d", &b);
G[i].push_back(b);
}
}
input_query();
tarjan(1, 0);
rep(i, 1, Q)
printf("%d\n", ans[i]);
}
return 0;
}