Codeforces 1208B/C 最长不重复子串/构造行列异或和相同矩阵

1208B

题意:给你一个序列,让你删掉一个子串,问你怎样删,留下的部分是最长的不重复子序列。
思路:看的晓阳队的思想。问的是求删掉的子串,那么我们转化成 求剩下的最长不重复子串。
因为剩下的可能是右边一段或者左边一段或者两边合起来!所以:
离散化后复制一份放后面,然后尺取法求序列中间的最长不重复。
但是能做答案的只能是l从1开始或者横跨n和n+1的!
想想为什么。
因为只能删掉中间的
如果取中间的一段最长不重复子串 就得从两边拿 显然是不可能的
so要有l==1或者r>=n的限制(r可取n 是右部区间。r大于n 是右边与左边连续区间
才能作为最大值。
下面是AC代码。尺取法
离散化是nlogn的复杂度
尺取法是On的复杂度,可以接受。
还有就是不要只在增加为1的时候才去判,若增加为2再取收缩时 也有可能是最大!

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#define ll long long
#define inf 0x3f3f3f3f
#define sd(a) scanf("%d",&a)
#define sdd(a,b) scanf("%d%d",&a,&b)
#define cl(a,b) memset(a,b,sizeof(a))
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define dbg() printf("aaa\n")
using namespace std;
//注意开二倍数组!!!!
int a[4010],acopy[2010];
int num[2010];
int main() {
    int n;
    cl(num,0);
    sd(n);
    rep(i,1,n){
        sd(a[i]);
        acopy[i]=a[i];
    }
    sort(acopy+1,acopy+n+1);
    int size=unique(acopy+1,acopy+n+1)-(acopy+1);//注意这里!!!
    rep(i,1,n){
        a[i]=lower_bound(acopy+1,acopy+size+1,a[i])-acopy;
    }
    rep(i,1,n){//复制一遍
        a[n+i]=a[i];
    }//然后找最长不重复子序列
    int l=1,r=1;
    int len=0;//最长不重复子序列
    while(l<=n){//无需刻意控制长度为n 因为长度一定为n
        num[a[r]]++;
        while(num[a[r]]>1){
            num[a[l]]--;
            l++;
        }
        if(l==1||r>=n) {
            if(len<r-l+1) len=r-l+1;
        }
        r++;
    }
    printf("%d\n",n-len);
	return 0;
}
/*
10
1 100 100 1000 1000 100 10 1 1000 1
*/

1208C

题意:给你一个数n(n是4的倍数)
让你构造一个n* n的矩阵,满足行列异或和相等
思路:刚刚拿到这个题 是真的不会。。。
后来看了题解发现
首先因为某个数和自己异或 一定是0!
所以说我们只要安排,两个相同的数在同一行列就行了
注意 ,而这里不能相同。
但是我们可以让它们高位相同
什么意思?
来看:因为方阵n一定为4的倍数
所以说我们先把方阵分成四个部分
每个部分的都是n/2的方阵 而n/2一定是2的倍数!(这点很重要)
我们要做的是,四个小方阵,每个的同一位置,放相同的数*4,再各自加上0 1 2 3
什么道理?
乘以四就是各自左移两位,这样做保证了每行/列 高位有两个相同的数,低位有偶数个0/1/2/3!
这样每行每列异或和都为0!
思路写的很乱,总之就是,大方阵分成四个小方阵,每个小方阵每个相同位置的数 高位相同 低位分别是0 1 2 3 然后又因为每个小方阵都是偶数阶 所以保证了低位可以是偶数个相同的数异或 高位也有n/2个相同的数异或 最终异或结果都是0
下面是ac代码

int mp[1010][1010];
int main() {
	int n;
	sd(n);
	//应该是确定四分之一然后确定其他 而不是确定4x4再确定其他- -这个也行?
	int cnt=0;
	rep(i,1,n/2){//有了思路其实还挺好想的
		rep(j,1,n/2){//也就刚好是4的倍数 不然8 9都不行
			mp[i][j]=cnt*4;
			mp[i][j+n/2]=cnt*4+1;
			mp[i+n/2][j]=cnt*4+2;
			mp[i+n/2][j+n/2]=cnt*4+3;
			cnt++;
		}
	}
	rep(i,1,n){
		rep(j,1,n){
			printf("%d%c",mp[i][j],j==n?'\n':' ');
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值