1 vj团队5补题(上午)
https://vjudge.net/contest/643995
题解
2 cf r950(下午+晚上)
https://vjudge.net/contest/643996#google_vignette
1)2最大公约数非递减序列
https://www.luogu.com.cn/problem/CF1980D
重点
1.思维:删去一个ai时,需要删除ai与前后的公因数,并加上ai-1与ai+1的最大公因数。
2.思路:
代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define inf 1e8
using namespace std;
const int N = 2e5 + 10;
int T, n, a[N], b[N];
void solve() {
cin >> n;
For(i,1,n) cin >> a[i];
a[n+1] = a[0] = 0;
For(i,1,n-1) b[i] = __gcd(a[i], a[i+1]);
b[n] = inf;
int l = 1, r = n-1;
while(l <= n-1 && b[l+1] >= b[l]) l++;
while(r >= 1 && b[r-1] <= b[r]) r--;
if(l == n-2 || r == 2) {
puts("YES"); return ;
//即这时就直接删去第一个点或者最后一个点即可
}
For(i,1,n) {
int New = __gcd(a[i-1], a[i+1]);
//0ll:整数 0 显式地声明为 long long 类型
if(New >= b[max(0ll, i-2)] && New <= b[min(n, i+1)] && l >= i - 2 && r <= i + 1) {
//不太理解这个判断条件
//因为两个a组成一个b,所以i-2相当于a中i-2与i-1的公因,i+1就是i+1和i+2
//l左侧和r右侧都是正确的,所以修改区间应该>=l与r中间的区间
puts("YES"); return ;
}
}
puts("NO");
return ;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> T;
while(T--) solve();
return 0;
}
2)矩阵交换行列(思维)
https://www.luogu.com.cn/problem/solution/CF1980E
题意:
两个 n×m 矩阵,里面元素构成排列,你可以交换任意一列任意一行,求任意次操作后两个矩阵能否相同。
重点
无论如何交换,每一行每一列元素构成的集合不变。
思路:
1.由于矩阵中的元素是排列,并且我们每次只能交换两行或者两列。容易发现无论怎么交换同一行和同一列中的元素种类是不会改变的,只会改变相对位置。那么我们可以记录下矩阵a中每个元素所在的行和列的位置,再按照其在矩阵b,b矩阵的位置进行交换,交换完所有位置后,如果一致,那么即可完成操作,否则一定无法通过交换操作使得矩阵 变成矩阵
2.
代码1
// 直接对于行和列开两个数组记录一下矩阵a中行和列转移到了矩阵b中行和列对应的编号,如果发现冲突则无解。
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int T,n,m,a[N][2],b[N][2],h[N],l[N];
signed main()
{
ios::sync_with_stdio(0);
cin>>T;
while (T--)
{
cin>>n>>m;
for (int i=1; i<=n; i++)
{
h[i]=0;
}
for (int j=1; j<=m; j++)
{
l[j]=0;
}
for (int i=1; i<=n; i++)
{
for (int j=1; j<=m; j++)
{
int x;
cin>>x;
a[x][0]=i;
a[x][1]=j;
//分别表示x所在的行是i,列是j
}
}
for (int i=1; i<=n; i++)
{
for (int j=1; j<=m; j++)
{
int x;
cin>>x;
b[x][0]=i;
b[x][1]=j;
}
}
bool f=0;
for (int i=1; i<=n*m; i++)
{
/*h和l分别表示的是a矩阵中的行和列在b矩阵中对应的位置,
我是对于矩阵中的n*m个数,
用当前数字在矩阵中的位置来更新h和l数组,
else if 里面的内容就是更新的时候发现矛盾是输出no*/
if (!h[a[i][0]])
{
//i元素所在的行
h[a[i][0]]=b[i][0];
}
else if (h[a[i][0]]!=b[i][0])
{
//也就是说现根据每行第一个元素交换,然后检查其他元素是否冲突
//即h[i]是第i行。i这个元素在a里在x行,在b里在y行。这两行必须相等
f=1;
cout<<"NO"<<endl;
break;
}
if (!l[a[i][1]])
{
l[a[i][1]]=b[i][1];
}
else if (l[a[i][1]]!=b[i][1])
{
f=1;
cout<<"NO"<<endl;
break;
}
}
if (!f) cout<<"YES"<<endl;
}
return 0;
}
代码2
void Showball(){
int n,m;
cin>>n>>m;
vector<vector<int>> a(n,vector<int>(m)),b(n,vector<int>(m));
vector<int> row(n*m),col(n*m);
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>a[i][j];
a[i][j]--;
row[a[i][j]]=i;
col[a[i][j]]=j;
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>b[i][j];
b[i][j]--;
}
}
for(int i=0;i<n;i++){
int r=row[b[i][0]];
swap(a[i],a[r]);
for(int j=0;j<m;j++){
row[a[i][j]]=i;
row[a[r][j]]=r;
}
}
for(int j=0;j<m;j++){
int c=col[b[0][j]];
for(int i=0;i<n;i++){
swap(a[i][j],a[i][c]);
col[a[i][j]]=j;
col[a[i][c]]=c;
}
}
cout<<(a==b?"YES\n":"NO\n");
}
3 cf团队赛6补题(下午)
思维转化
题意:n个需要修理的网络,每个机器能同时修理k个,问修理这n个需要多少机器。
思路:找间隔小于一千的序列,这个序列里最长的,他的网络个数/k就是至少需要的机器数量,因为间隔大于1000的其实只要一台机器就能处理。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n,k;
int jude(int x)
{
if(x%k==0) return x/k;
else return x/k+1;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> k;
int a[N];
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
int sum = 0;
int st = 1;
//枚举每一段的终点,找他最前面的第一个间隔小于1000的,这一段就是子序列之一。
for (int ed = 1; ed <= n; ed++) {
while (a[ed] - a[st] >= 1000) {
st++;
}
int count = ed - st + 1;
sum = max(sum, jude(count));
}
cout << sum << endl;
return 0;
}