BestCoder Round #81

只会做前三道啊,还有很长的路要走啊喂


1001 Machine


有一个机器,它有 m (2\leq m\leq 30)m(2m30) 个彩灯和一个按钮。每按下按钮时,最右边的彩灯会发生一次变换。变换为:

1. 如果当前状态为红色,它将变成绿色;

2.如果当前状态为绿色,它将变成蓝色;

3.如果当前状态为蓝色,它将变成红色,并且它左边的彩灯(如果存在)也会发生一次变换。

初始状态下所有的灯都是红色的。
询问按下按钮 n (1\leq n< {2}^{63})n(1n<263) 次以后各个彩灯的颜色。

题解

红、绿、蓝分别表示0、1、2,每次操作就相当于+1,原问题就转化为求nn的三进制

表示的最低的mm位,即求 nn mod 3^m3m的三进制表示。

复杂度 O(m)O(m)

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		long long m,n;
		scanf("%I64d%I64d",&m,&n);
		int a[32];
		memset(a,0,sizeof(a));
		int time = 3;
		for(int i=m-1;i>=0;i--){
			if(n!=0)
				a[i] = n%time;
			n/=3;
		}
		for(int i=0;i<m;i++){
			if(a[i]==0)	printf("R");
			else if(a[i]==1) printf("G");
			else if(a[i]==2)	printf("B");
		}
		printf("\n");
	} 
	return 0;
}
 
 

1002  Matrix

有一个nnmm列的矩阵(1 \leq n \leq 1000 ,1 \leq m \leq 1000 )(1n1000,1m1000),在这个矩阵上进行qq  (1 \leq q \leq 100,000)(1q100,000) 个操作:

1 x y: 交换矩阵MM的第xx行和第yy(1 \leq x,y \leq n)(1x,yn);
2 x y: 交换矩阵MM的第xx列和第yy(1 \leq x,y \leq m)(1x,ym);
3 x y: 对矩阵MM的第xx行的每一个数加上y(1 \leq x \leq n,1 \leq y \leq 10,000)y(1xn,1y10,000);
4 x y: 对矩阵MM的第xx列的每一个数加上y(1 \leq x \leq m,1 \leq y \leq 10,000)y(1xm,1y10,000);

题解

对于交换行、交换列的操作,分别记录当前状态下每一行、每一列是原始数组的哪一行、哪一列即可。

对每一行、每一列加一个数的操作,也可以两个数组分别记录。注意当交换行、列的同时,也要交换增量数组。

输出时通过索引找到原矩阵中的值,再加上行、列的增量。

复杂度O(q+mn)O(q+mn)



#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
struct node{
	long long v,c;
};
node x[1010],y[1010];
long long a[1010][1010];
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int n,m,p;
		scanf("%d%d%d",&n,&m,&p);
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				scanf("%I64d",&a[i][j]);
			}
		}
		for(int i=1;i<=n||i<=m;i++){
			x[i].v = y[i].v = 0;
			x[i].c = y[i].c = i;
		}
		for(int i=0;i<p;i++){
			int q,g,h;
			scanf("%d%d%d",&q,&g,&h);
			if(q==1){
				swap(x[g].c,x[h].c);
			}
			else if(q==2){
				swap(y[g].c,y[h].c);
			}
			else if(q==3){
				x[x[g].c].v += h;
			}
			else if(q==4){
				y[y[g].c].v += h;
			}
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				printf("%I64d",a[x[i].c][y[j].c] + x[x[i].c].v + y[y[j].c].v);
				if(j!=m)	printf(" ");
				else printf("\n");
			}
			
		}
	}
	return 0;
}


String


有一个 10\leq10长度\leq 1,000,0001,000,000 的字符串,仅由小写字母构成。求有多少个子串,包含有至少k(1 \leq k \leq 26)k(1k26)个不同的字母?

有一个明显的性质:如果子串(i,j)(i,j)包含了至少kk个不同的字符,那么子串(i,k),(j < k < length)(i,k),(j<k<length)也包含了至少kk个不同字符。

因此对于每一个左边界,只要找到最小的满足条件的右边界,就能在O(1)O(1)时间内统计完所有以这个左边界开始的符合条件的子串。

寻找这个右边界,是经典的追赶法(尺取法,双指针法)问题。维护两个指针(数组下标),轮流更新左右边界,同时累加答案即可。复杂度 O(length(S))O(length(S))

<span style="font-size:18px;">#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;
#define MAX 10000009
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		char a[MAX];
		int k;
		scanf("%s%d",a,&k);
		int r=-1,ans = 0;
		long long sum = 0 ;
		int n = strlen(a);
		int book[29];		
		memset(book,0,sizeof(book));
		for(int i=0;i<n;i++){
			while(ans<k&&r<n){
				r++;
				if(++book[a[r]-'a']==1)
					ans++;
			}
			if(ans<k)	break;
			sum += (long long)(n - r) ;
			if(--book[a[i]-'a']==0)
				ans--;
		}
		printf("%I64d\n",sum);
	}
	return 0;
}
</span>




你可能感兴趣的:(BestCoder)