感觉自己基础不够扎实, 思维不够灵敏,所以最近主要在刷cf和abc的题。
AtCoder Beginner Contest 310 D - Peaceful Teams
题目大意:给定n,t,m,n表示有多少个人,t表示队伍个数,m表示敌人关系数量
求:把n个人分为t支队伍有多少个方案数(敌人不能在一个队)
由于数据量太小,直接暴搜。
vector<int>tim; //存储每一个队伍的代表人物
int ey[15]; //存储每一个人的敌人(ey[i]的二进制上为1的表示是敌人)
int n, t, m;
int ans;
void dfs(int now) {
if(now > n) {
ans += (tim.size() == t);
return;
}
for(int v : tim) {
if(!(ey[v] & (1 << (now - 1))) ) {
int ey1 = ey[v];
ey[v] |= ey[now]; //敌人累加
dfs(now + 1);
ey[v] = ey1; //回溯
}
}
if(tim.size() < t) { //添加到队伍中
tim.push_back(now);
dfs(now + 1);
tim.pop_back();
}
}
void solve() {
cin >> n >> t >> m;
rep(i, 1, m) {
int a, b;
cin >> a >> b;
ey[a] |= 1 << (b - 1);
ey[b] |= 1 << (a - 1);
}
tim.reserve(t);
dfs(1);
cout << ans << endl;
}
牛客练习赛 112 B qsgg and Subarray
因为0&什么都是0,不难知道一个区间只要为0,那么所有包含这个区间的值也为0
数据为1e9,所以我们枚举到31位,用lst存每一位为0的最大下标,相当于右端点
最后枚举lst中的最小值设为左端点,这时右端点不动,所有包含该区间的的区间数就为左端点的值
const int N = 1e6 + 10;
int a[N], lst[32];
void solve() {
int n;
cin >> n;
rep(i, 1, n) {
cin >> a[i];
}
ll ans = 0;
rep(i, 1, n) {
rep(j, 0, 31) {
if(!((a[i] >> j) & 1)) {
lst[j] = i;
}
}
int minn = 1e9;
rep(j, 0, 31) {
minn = min(minn, lst[j]);
}
ans += minn;
}
cout << ans << endl;
}
AtCoder Regular Contest 164 B Switching Travel
题目大意:n个顶点,m条边,无向图,每一个顶点都有一种颜色,0为白,1为黑。
可以进行的操作:选一个顶点作为起点出发,可以移动到与自身颜色不同的顶点上,移动后上一个顶点变色(白<->黑)。
问是否可以回到起点。
思路:很自然的想到要回到起点,肯定要有一个环(首尾相连),而且因为每走过一个点,该点就会变色,所以首尾初始时,一定
要是同一个颜色。
做法:用并查集维护连通分量,检查每个连通分量中是否有颜色相同的顶点,若有,则输出Yes,若检查完了之后还没有输出Yes,则
输出No。
const int N = 2e5 + 10;
int pre[N];
int col[N];
struct {
int u, v;
}g[N];
int find(int f) {
if(pre[f] == f) return f;
else return pre[f] = find(pre[f]);
}
void solve() {
int n, m;
cin >> n >> m;
rep(i, 1, m) {
cin >> g[i].u >> g[i].v;
}
rep(i, 1, n) {
cin >> col[i];
pre[i] = i;
}
rep(i, 1, m) {
int u = g[i].u, v = g[i].v;
if(col[u] != col[v]) {
pre[find(u)] = pre[find(v)];
}
}
rep(i, 1, m) {
int u = g[i].u, v = g[i].v;
if(col[u] == col[v]) {
if(pre[find(u)] == pre[find(v)]) {
cout << Yes << endl;
return;
}
}
}
cout << No << endl;
}
AtCoder Regular Contest 164 Reversible Card Game
题目大意:n张双面均有数字的卡片,A先选择一张翻面,B再选一张取出,并获得正面的数字分值。
求B可以获得的最大分值,A要尽量减少B获得的分值。
贪心:A要选取正面和反面差值最大的翻,B也要选择差值最大的拿。
做法:优先队列。
struct node {
int a, b;
bool operator < (const node& temp) const {
return (temp.a - temp.b) > (a - b);
}
};
void solve() {
int n;
cin >> n;
priority_queue<node>q;
rep(i, 1, n) {
int a, b;
cin >> a >> b;
q.push({a, b});
}
ll ans = 0;
while(!q.empty()) {
node p = q.top();
q.pop();
q.push({p.b, p.a});
p = q.top();
q.pop();
ans += p.a;
}
cout << ans << endl;
}
每天刷一下cf和abc,以及学算法。