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.思路:image

代码
#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.
image

代码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;
}
posted on 2024-07-30 16:16  Hoshino1  阅读(1)  评论(0编辑  收藏  举报