复建补题记录了属于是
A.two towers
题意:
给两个由红色块和蓝色块搭成的塔, 每次操作可以把某个塔塔顶的方块放到另一个塔的塔顶,问是否可以通过任意次操作,使得两个塔的任意两个相邻方块颜色不同。
思路:
考虑一种极端情况,把一个塔完全接到另一个塔上(虽然并不允许)然后遍历这个串,如果其中有一组同色色块相连,我们就可以从这个位置分成两个塔,而如果有一组以上,那无论我们怎么分都一定会有同色色块相连。
Code
#include<bits/stdc++.h>
#define debug(x) cerr << #x << "->" << x << endl;
#define int long long
using namespace std;
const int maxn = 2e5 + 10;
const int mod = 1e9 + 7;
void solve()
{
int n,m;
cin >> n >> m;
string a,b;
cin >> a >> b;
reverse(b.begin(),b.end());
a += b;
int cnt = 0;
for(int i = 1;i < a.size();i ++)
if(a[i] == a[i - 1])
cnt ++;
if(cnt <= 1) cout << "yes" << '\n';
else cout << "no" << '\n';
}
signed main()
{
int tt;
cin >> tt;
while(tt --)
solve();
}
B.Ideal Point
题意
给n条线段,定义f(x)为覆盖x的线段的数量,当一个点x的f(x)大于其他任意一点y的f(y),我们称这个f(x)是ideal的,给一个点k,问能不能通过移除任意跳线段使得k成为ideal的。
思路
所有不包含k的线段都直接去除,接下来考虑包含k的。我们假设有两条线段包含k,切这两条线段唯一的交点为k,那么此时k就是ideal的,那么我们只要确定有这两条线段存在,把其他的线段全部删除即可,如果找不到这么两条线段,就无法使k成为ideal。
Code
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int maxn = 1030 + 10;
void solve()
{
int n,k,flag = 0,flag0 = 0;
cin >> n >> k;
vector<PII>p(n + 1);
for(int i = 1;i <= n;i ++)
{
int x,y;
cin >> x >> y;
if(x == k) flag = 1;
if(y == k) flag0 = 1;
}
if(flag && flag0) puts("YES");
else puts("NO");
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int tt;
cin >> tt;
while(tt --)
solve();
}
C.Tea Tasting
题意
有n杯茶和n个人,每杯茶有ai毫升,每个人每次最多喝bi毫升。
第一轮,第i个人喝第i杯茶,每个人喝下min(ai,bi)毫升,每杯茶减少相同毫升。
第二轮,第i个人喝第i - 1杯茶,第一个不喝,每个人喝下min(ai - 1,bi)毫升,每杯茶减少相同毫升。
...
以此类推,问最后一轮结束后每个人能喝到多少茶。
思路
手模一下,发现第i杯茶会被第 i ~ n 这些人喝,而且每杯茶会被喝完,我们做一个b的前缀和数组sunb,对于每杯茶二分查找他会被第几个人喝完,假如被第j个人喝完,那i ~ j - 1的人都会喝到bi毫升,第i个人会喝到a[i] - sum[j - 1] + sum[i - 1]毫升,用差分数组维护一下每个人喝到了几次bi,瞎搞一通就ok了
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int maxn = 1030 + 10;
void solve()
{
int n;
cin >> n;
vector<int>a(n + 1),b(n + 1),sum(n + 1),dif(n + 1),res(n + 1);
for(int i = 1;i <= n;i ++)
cin >> a[i];
for(int i = 1;i <= n;i ++)
cin >> b[i];
for(int i = 1;i <= n;i ++)
sum[i] = sum[i - 1] + b[i];
for(int i = 1;i <= n;i ++)
{
int l = 1,r = n + 1;
while(l < r)
{
int mid = l + r >> 1;
if(sum[mid] - sum[i - 1] >= a[i]) r = mid;
else l = mid + 1;
}
if(l == n + 1) dif[i] ++;
else
{
dif[i] ++;
dif[l] --;
res[l] += (a[i] - (sum[l - 1] - sum[i - 1]));
}
}
int tot = 0;
for(int i = 1;i <= n;i ++)
{
// cout << res[i] << " \n"[i == n];
tot += dif[i];
res[i] += (tot * b[i]);
cout << res[i] << " \n"[i == n];
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int tt;
cin >> tt;
while(tt --)
solve();
}
D.Triangle Coloring
题意
给一个含n个点的带权无向图(n % 6 == 0),这个图被分成n/3个连通块,第i个连通块内点的标号为i,i+1,i+ 2,现在把这n个点染成红色和蓝色,要求红色点和蓝色点各占n/2,定义W为图中连接异色两点的边的边权和,问有多少种染色方式使得W最大。
思路
首先如果W最大,则不应该存在三条边均同色的连通块,而又要求红蓝数量相等,那么应该有一半的环染成红红蓝,另一半染成蓝蓝红,C(n/3,n/6)为环染色的情况,接下来考虑每个环有一种染法,优先使最大的两条边异色,而如果有两条边相等且都不是最大,那么有两种染法,如果三条边均相等,那么有三种染法,遍历计算ans即可。
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int mod = 998244353;
const int maxn = 3e5;
int f[maxn];
int q_pow(int a,int b)
{
int res = 1;
while(b)
{
if(b & 1) res = res * a % mod;
b >>= 1;
a = a * a % mod;
}
return res;
}
int inv(int p)
{
return q_pow(p,mod - 2);
}
void solve()
{
int n;
cin >> n;
vector<int>w(n + 1);
for(int i = 1;i <= n;i ++) cin >> w[i];
int ans = 1;
for(int i = 1;i <= n;i += 3)
{
vector<int>b = {w[i], w[i + 1], w[i + 2]};
sort(b.begin(),b.end());
if(b[0] == b[1] && b[1] == b[2]) ans = (ans * 3) % mod;
if(b[0] == b[1] && b[1] < b[2]) ans = (ans * 2) % mod;
}
int info = ((f[n / 3] * inv(f[n / 6])) % mod * inv(f[n / 3 - n / 6])) % mod;
cout << ans * info % mod << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
f[0] = 1;
for(int i = 1;i <= maxn;i ++)
f[i] = (f[i - 1] * i) % mod;
// int tt;
// cin >> tt;
// while(tt --)
solve();
}