• Codeforces Round #641 (Div. 2) A-E(1350,1349)


    这场好毒瘤,C不特判+不知道哪里写炸导致一直过不去,赛后换了写法才过/kk
    然后下分到1600,结果还是不能记分打div3/kk

    CF1350 A. Orac and Factors

    https://codeforces.com/problemset/problem/1350/A
    给出 (nle 10^6,kle 10^9),让 (n) 每次加上自己的最小因数,这样加 (k)

    • (n) 是偶数,那么每次加的最小因数都是 (2),答案 (n+2k)
    • 奇数,它的所有因数肯定都是奇数,那么先枚举出它的最小因数 (x),加上 (x) 就变成了偶数,按照偶数的处理方法再加 (k-1) 次就行,答案 (n+x+2(k-1))
    int main(){int T=read();while(T--){
    	LL n=read(),k=read();
    	if(n&1){
    		for(reg int i=3;;i++)if(!(n%i)){
    			n+=i;break;
    		}
    		k--;
    	}
    	std::printf("%lld
    ",n+2*k);
    }
    	return 0;
    }
    

    CF1350 B. Orac and Models

    https://codeforces.com/problemset/problem/1350/B
    给出一列数,要求选其中一些数,符合:

    • 排列顺序按照在原数列中的顺序排
    • 以上面的排列方式,数大小递增
    • 以上面的排列方式,相邻两数在原数列中的下标,前一个数是后一个数的因数

    求最多能选几个数

    没想到div2B就会出简单的dp
    (f_i) 为以 (i) 开头,最多能选几个
    那么倒着枚举,对于每个 (i)(f_i=max(f_j mid i ext{ 是 }j ext{ 的因数,且} a_j>a_i)+1)
    (a) 就是原数列,转移式子比较显然

    int a[100006],f[100006];
    int main(){int T=read();while(T--){
    	int n=read();
    	for(reg int i=1;i<=n;i++) a[i]=read();
    	int ans=0;
    	for(reg int i=n;i;i--){
    		f[i]=0;
    		for(reg int j=i+i;j<=n;j+=i)
    			if(a[j]>a[i]) f[i]=std::max(f[i],f[j]);
    		f[i]++;
    		ans=std::max(ans,f[i]);
    	}
    	std::printf("%d
    ",ans);
    }
    	return 0;
    }
    

    CF1349 A. Orac and LCM

    https://codeforces.com/problemset/problem/1349/A
    给出数列 (a),求 (gcd({operatorname{lcm}({a_i,a_j}) | i<j}))
    就是对于每一对 (a_i,a_j),让它们求一个 (operatorname{lcm}),放到一个新数列里,然后再求这个新数列的 (gcd)

    把每个数分解一下,设:

    [a_i=prod_{p_jin prime} p_j^{m_{ij}} ]

    则:

    [operatorname{lcm}(a_i,a_j)=prod_{p_kin prime} p_k^{t_k},t_k=max(m_{ik},m_{jk}) ]

    [gcd(a_i,a_j)=prod_{p_kin prime} p_k^{t_k},t_k=min(m_{ik},m_{jk}) ]

    说人话,就是取 (operatorname{lcm}) 的时候就是取质因数质数的较大值,(gcd) 就是取较小值

    那么要求的答案:

    [prod_{p_kin prime} p_k^{t_k},t_k=min({max(m_{ik},m_{jk}) | i<j}) ]

    就是每个指数,都是取每两对数对应的指数,取 (max),再在这些 (max) 里取一个 (min)
    那么,对于每一个质因数,我们找出数列中每个数它的指数的最小值和次小值,让答案乘上它的次小值次幂就行了
    还要用 (vis) 数组标记一下一个质因数在数列的数中出现了几次,可以看注释

    LL a[100005];
    int min2[200006],min[200006],vis[200006];
    int prime[100005],notprime[200006];
    inline void get_prime(int n){
    	for(reg int i=2;i<=n;i++){
    		if(notprime[i]) continue;
    		prime[++prime[0]]=i;
    		for(reg int j=i+i;j<=n;j+=i) notprime[j]=1;
    	}
    }
    int main(){
    //		std::freopen("tmp.txt","r",stdin);
    	int n=read();
    	for(reg int i=1;i<=n;i++) a[i]=read();
    	if(n==2) return std::printf("%lld",a[1]/std::__gcd(a[1],a[2])*a[2]),0;
    	std::memset(min,0x7f,sizeof min);std::memset(min2,0x7f,sizeof min2);
    	LL ans=1;
    	get_prime(200000);
    	for(reg int i=1;i<=n;i++){
    		int num,sqrt=std::sqrt(a[i]);
    		for(reg int j=1;j<=prime[0];j++){
    			if(a[i]<prime[j]||sqrt<prime[j]) break;
    			if(!(a[i]%prime[j])){
    				num=0;
    				while(!(a[i]%prime[j])) a[i]/=prime[j],num++;
    				if(num<min[prime[j]]) min2[prime[j]]=min[prime[j]],min[prime[j]]=num;
    				else if(num<min2[prime[j]]) min2[prime[j]]=num;
    				vis[prime[j]]++;
    			}
    		}
    		if(a[i]>1){
    			if(1<min[a[i]]) min2[a[i]]=min[a[i]],min[a[i]]=1;
    			else if(1<min2[a[i]]) min2[a[i]]=1;
    			vis[a[i]]++;
    		} 
    	}
    	for(reg int i=2;i<=200000;i++)
    		if(vis[i]==n) for(reg int j=1;j<=min2[i];j++) ans*=i;
    		//每个数都包含这个质数,所以用 min2 
    		else if(vis[i]==n-1) for(reg int j=1;j<=min[i];j++) ans*=i;
    		//有一个数不包含它,不包含它的那个数是 0,所以 min 其实才是第二小的
    	std::printf("%lld",ans);
    	return 0;
    }
    

    CF1349 B. Orac and Medians

    https://codeforces.com/problemset/problem/1349/B
    给出一列数 (a),每次可以将 (a) 的一个区间改成这个区间数的中位数,问能不能将数列全都变成 (k)(给定的)
    此处,偶数长度序列的中位数,是中间靠左的那个数

    如果没有 (k),肯定不行
    (k),且 (k) 旁边有一个大于等于 (k) 的数,那么可以选这两个数的区间,让它变成两个连续的 (k),然后一个一个扩大区间,最终使得整个序列都变成 (k)

    那么考虑怎么让 (k) 旁边出现大于等于 (k) 的数
    如果有两个大于等于 (k) 的数相距不超过 (2),也就是中间最多夹一个其他数,那么一定可以
    因为如果是这种情况,则一定可以向上面描述的那样,一个一个的扩大区间,使得任意包含这两个数的区间都变成这两个数,那么就可以让 (k) 旁边出现大于等于 (k) 的数
    否则一定不行,因为任意一个长度为 (m) 的区间,如果包含 (k),并且想让 (k) 作为它的中位数,则大于等于 (k) 的数至少有 (ceilfrac{m}{2} ceil)
    所以如果任意两个大于等于 (k) 的数相距都大于 (2),则在任意长度为 (m) 的区间内,不可能出现 (ceilfrac{m}{2} ceil) 个大于等于 (k) 的数

    所有是个结论题

    int a[100005];
    int main(){int T=read();while(T--){
    	int n=read(),k=read(),flag=0;
    	for(reg int i=1;i<=n;i++){
    		a[i]=read();
    		if(a[i]==k) flag=1;
    	}
    	a[n+1]=a[n+2]=a[n+3]=0;
    	if(!flag){
    		std::puts("no");continue;
    	}
    	if(n==1&&a[1]==k) goto YES;
    	for(reg int i=1;i<=n;i++)if(a[i]>=k){
    		if(a[i+1]>=k||a[i+2]>=k) goto YES;
    	}
    	std::puts("no");continue;
    	YES:;
    	std::puts("yes");
    }
    	return 0;
    }
    

    CF1349 C. Orac and Game of Life

    https://codeforces.com/problemset/problem/1349/C
    给出一个 (n imes m) 的格子,每个格子是 (1)(0)
    每次操作,对于每个格子,如果周围有和他一样数字的格子,就改变数字,如果没有,不变

    把格子分成两类,第一类是周围有和他一样数字的格子,第二类是没有

    • 第一类格子永远是第一类,因为它旁边相同颜色的格子也是第一类,会跟他一起变动,所以它旁边一直有和他数字相同的格子
    • 如果第二类旁边有一个第一类,那么第一类会在一次变动后改变颜色,此时,它应该和第二类的这个格子数字相同(因为一开始是不同的),那么,这个第二类就变成了第一类
    • 那么第一类的格子每次会将它旁边的格子变成第一类,所以对于一个第二类的格子,它变成第一类所需要的步数,就是和它曼哈顿距离最小的一个第一类格子的曼哈顿距离

    所以,我们只要 bfs 出这个所需的步数,然后就是每操作一次,就改变一次,可以用异或得出

    int a[1006][1006],type[1006][1006];
    int num[1006][1006];
    int q[3000006],head,tail,vis[1006][1006];
    int n,m;
    char s[1006];
    const int dx[4]={1,-1,0,0};
    const int dy[4]={0,0,1,-1};
    inline int no(int x,int y){
    	if(x<1||y<1||x>n||y>m) return 1;
    	if(vis[x][y]) return 1;
    	return 0;
    }
    inline int check(int i,int j){
    	if(i-1>0&&a[i][j]==a[i-1][j]) return 1;
    	if(i+1<=n&&a[i+1][j]==a[i][j]) return 1;
    	if(j-1>0&&a[i][j-1]==a[i][j]) return 1;
    	if(j+1<=m&&a[i][j]==a[i][j+1]) return 1;
    	return 0;
    }
    inline void bfs(){
    	reg int x,y,x_,y_,step;
    	while(tail<=head){
    		x=q[tail++];y=q[tail++];step=q[tail++]+1;
    		for(reg int k=0;k<4;k++){
    			x_=x+dx[k];y_=y+dy[k];
    			if(no(x_,y_)) continue;
    			vis[x_][y_]=1;
    			if(type[x_][y_]==2) num[x_][y_]=step;
    			q[++head]=x_;q[++head]=y_;q[++head]=step;
    		}
    	}
    }
    int main(){
    	n=read();m=read();int Q=read();
    	for(reg int i=1;i<=n;i++){
    		std::scanf("%s",s+1);
    		for(reg int j=1;j<=m;j++) a[i][j]=s[j]-48;
    	}
    	head=0;tail=1;
    	for(reg int i=1;i<=n;i++)for(reg int j=1;j<=m;j++){
    		if(check(i,j)) type[i][j]=1,q[++head]=i,q[++head]=j,q[++head]=0,vis[i][j]=1;
    		else type[i][j]=2;
    	}
    	bfs();
    	reg int x,y;LL p;
    	while(Q--){
    		x=read();y=read();p=read();
    		if(type[x][y]==1) std::printf("%d
    ",a[x][y]^(p&1));
    		else{
    			if(!num[x][y]) std::printf("%d
    ",a[x][y]);//永远不会变
    			else if(p<=num[x][y]) std::printf("%d
    ",a[x][y]);
    			else std::printf("%d
    ",a[x][y]^((p-num[x][y])&1));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    《构建之法》阅读笔记二
    《构建之法》阅读笔记一
    软件工程个人课程总结
    纯随机数生成器
    递归方法
    素数的输出
    字母统计|英语的26 个字母在一本小说中是如何分布的
    类的声明
    FileInputStream类与FileOutputStream类
    验证码|程序登录界面
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/12880636.html
Copyright © 2020-2023  润新知