191130Practice

这个月复习半期,好像有两周没上信息课
昨天终于开始了(想念OI的味道)

然鹅今天考试qwq
第一次考第一诶~ (虽然是在菜鸡班)
主要是因为巨佬都把文件名写错了:D

T1 Niven

模拟菜题

sol

#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
int niven,n;

inline int in{
	int i=0,f=1;char ch;
	while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
	if(ch=='-')ch=getchar(),f=-1;
	while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
	return i*f;
}

inline int Load(int n){
	int a=1,sum=0,tmp=n;
	while(tmp){
		sum+=a*(tmp%10);
		a*=niven;
		tmp/=10;
	}
	return sum;
}

inline int Sum(int n){
	int sum=0,tmp=n;
	while(tmp){
		sum+=tmp%10;
		tmp/=10;
	}
	return sum;
}

int main(){
	
//	freopen("niven.in","r",stdin);
//	freopen("niven.out","w",stdout);
	
	niven=10;
	while(niven){
		niven=in;
		if(!niven)return 0;
		n=in;
		if(Load(n)%Sum(n)==0)printf("yes\n");
		else printf("no\n");
	}
	return 0;
}

T2 Sub

很庆幸zgs的数据太小、电脑太快
我O(N3)的暴力模拟都过了
sol

//O(n^3)可能T 
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
#pragma GCC optimize(2)
int n,len,m;
char ch[(int)2e3+10];
int ansl,ansh;

inline int in{
	int i=0,f=1;char ch;
	while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
	if(ch=='-')ch=getchar(),f=-1;
	while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
	return i*f;
}

int main(){
	
//	freopen("sub.in","r",stdin);
//	freopen("sub.out","w",stdout);
	
	n=in;
	gets(ch);
	len=strlen(ch);
	
	for(re int i=0;i<len-n;i++)
		for(re int j=i+n;j<len;j++){
			if((j-i)%2==0)continue;
			int l=i,r=((i+j)>>1)+1,h=((j-i)>>1)+1;
			for(re int k=0;k<h;k++)
				if(ch[l+k]!=ch[r+k])m++;
			if(m<=n&&h>ansh)ansl=l,ansh=h;
			m=0;
		}
	if(!ansh){
		printf("Not found\n");
		return 0;
	}
	printf("%d ",ansh*2);
	for(re int i=0;i<ansh*2;i++)
		printf("%c",ch[ansl+i]);
	
	return 0;
}

改进的算法

用前缀和的思想
忽略字符,因为我们只需要比较字符不一样
为了不一直比较,直接枚举长度然后确定二者是否相同
那一次比较就是查询一段区间的和
我实在是看不懂zgs的丑陋至极的代码(if和while之间他竟然不换行T_T)
大概理解了一下:

#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
int n,len;
char ch[2010];
bool diff[2010];
int total[2010];

inline int in{
	int i=0,f=1;char ch;
	while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
	if(ch=='-')ch=getchar(),f=-1;
	while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
	return i*f;
}

int main(){
	
	n=in;
	gets(ch);
	len=strlen(ch);
	
	bool found=false;
	for(re int i=(len>>1);i>=1;i--){
		
		for(re int j=i;j<=len;j++)
			diff[j]=(ch[j]!=ch[j-i])?true:false;
		
		total[i]=diff[i];
		for(re int j=i+1;j<(i<<1);j++)
			total[j]=total[j-1]+diff[j];
		for(re int j=(i<<1);j<len;j++)
			total[j]=total[j-1]+diff[j]-diff[j-i];
		
		for(re int j=(i<<1)-1;j<len;j++)
			if(total[j]<=n){
				found=true;
				char ans[2010];
				int tot=0;
				for(re int k=j-(i<<1)+1;k<=j;k++)
					ans[tot++]=ch[k];
				ans[(i<<1)]=0;
				printf("%d %s\n",(i<<1),ans);
				break;
			}
		
		if(found)break;
	}
	if(!found)puts("Not found");
	return 0;
}

T3 News

读题有点日隆
他说的是从一个点开始,遍历(带边权)所用时间最短的

竟然没有想到用Floyd算法
数据小,O(N3)就搞定了( N [ 1 , 100 ] N \in [1,100]
联通块判断:如果!Map[i][j]则disjoint

Floyd有点坑——先枚举i,j,k中哪一个是有考究的
研究一下

sol

#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
#define INF 0x7fffffff
int n;
int Map[110][110];

inline int in{
	int i=0,f=1;char ch;
	while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
	if(ch=='-')ch=getchar(),f=-1;
	while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
	return i*f;
}

inline void Floyd(){
	for(re int k=1;k<=n;k++)
		for(re int i=1;i<=n;i++)
			if(Map[i][k]&&i!=k)
				for(re int j=1;j<=n;j++)
					if(Map[k][j]&&i!=j&&j!=k)
						if(!Map[i][j]||(Map[i][j]>Map[i][k]+Map[k][j]))
							Map[i][j]=Map[i][k]+Map[k][j];
}

int main(){
	n=in;
	for(re int i=1;i<=n;i++){
		int x=in;
		for(re int j=1;j<=x;j++)
			Map[i][in]=in;
	}
	
	Floyd();
	
	int mint=INF,time=0,mini=0;
	for(re int i=1;i<=n;i++){
		time=0;
		for(re int j=1;j<=n;j++)
			if(i!=j){
				if(time<Map[i][j])time=Map[i][j];
				else if(Map[i][j]==0){
					time=INF;
					break;
				}
			}
		if(time<mint){
			mini=i;
			mint=time;
		}
	}
	
	if(mint==INF)printf("disjoint\n");
	else printf("%d %d\n",mini,mint);
	return 0;
}

T4 Arrange

先说这个结论:
感性认知(一会儿来证),矩阵中的每一排在排序后的数组中是连续的

很明显的二分:二分ans
构造的出来就往下缩
不行就往上走
O ( N l o g 2 N ) O(Nlog_2N)

sol

#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
int n,r,c;
int p[(int)5e5+10];
int ans;

inline int in{
	int i=0,f=1;char ch;
	while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
	if(ch=='-')ch=getchar(),f=-1;
	while(ch>='0'&&ch<='9')i=(i<<1)+(i<<3)+ch-48,ch=getchar();
	return i*f;
}

inline int check(int x){
	int cnt=0;
	for(re int i=1;i<=n-c+1;){
		if(p[i+c-1]-p[i]<=x)cnt++,i+=c;
		else i++;
	}
	return cnt;
}

int main(){
	n=in,r=in,c=in;
	for(re int i=1;i<=n;i++)p[i]=in;
	
	sort(p+1,p+n+1);
	
	int l=0,h=(int)1e9+1;
	while(l<=h){
		int mid=(l+h)>>1;
		if(check(mid)>=r)h=mid-1,ans=mid;
		else l=mid+1;
	}
	
	printf("%d\n",ans);
	return 0;
}

写二分的时候把r和h搞混了T_T

关于结论 “矩阵中的每一排在排序后的数组中是连续的” 的证明:
反证法,假设有一行不连续
对于一行 R i R_i
假设 P j [ R i , m i n , R i , m a x ] P_j \in [R_{i,min},R_{i,max}] P j R i P_j \notin R_i

s w a p ( P j , R i , m a x ) swap(P_j,R_{i,max})
F \Rightarrow F 不变

min(R[i])<=p[j]<=max(R[i])
swap(p[j],max(R[i])),不改变F

if(p[j]属于R[k]){
	
	if(A:min(R[k])<=min(R[i]))
		swap(p[j],min(R[i]))不增大F
	
	else if(B:max(R[k])>=max(R[i]))
		swap(p[j],max(R[i]))不增大F
	
	else if(!A:min(R[k])>=min(R[i])&&!B:max(R[k])<=max(R[i])) 即均不满足上面两种情况
		swap(max(R[k]),max(R[i]))不增大F 
	
}

因此可以通过这些操作把每一行换成连续的
伪证毕

发布了26 篇原创文章 · 获赞 3 · 访问量 904

猜你喜欢

转载自blog.csdn.net/Antimonysbguy/article/details/103324065