AutoX安途杯中山大学程序设计校赛(同步赛)

传送门

1.A+B+C Problem

考察:模拟

思路
因为A+B+C的和要是1e6的倍数,那么枚举1e6的倍数(注意:从0开始算!!!),依次算出c的值,如果c的范围在0-1e6之间,就输出,如果>1e6了,那么后面增大总和算出的c更大,更不符合要求,直接输出-1。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6;

inline int read(){
    int k=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
    while(ch>='0'&&ch<='9'){
		k=k*10+ch-'0';
		ch=getchar();
	}
    return k*f;
}

void rd(long long &x){
    char c;
    for (x=0,c=getchar();c<48;c=getchar());
    for (;c>47;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
}


void solve(){
	int a,b,c;
	bool flag=false;
	a=read(),b=read();
	int k=0;
	while(1){
		ll x=k*N;
		c=x-a-b;
		if(c>=0&&c<N){
			flag=1;
			printf("%d\n",c);
		    return;
		}
		k++;
		if(c>=N){
			flag=0;
			break;
		}
	}
	if(!flag) puts("-1");
	
}

int main(){
	int t;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

2.Lucky Matrix

考察:观察模拟

思路
九宫格,横着竖着斜着的和要相等,且每个元素都要是整数。

那么什么时候一定构造不出呢?

把样例模拟一下发现,能够构造出来的都是:
i=(b+d)/2;
e=(a+i)/2;
即如果这两个算出来不是整数,就一定构造不出。
这两个算出来,那么总和就算出了,再依次算出其他的。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6;

inline int read(){
    int k=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
    while(ch>='0'&&ch<='9'){
		k=k*10+ch-'0';
		ch=getchar();
	}
    return k*f;
}

void rd(long long &x){
    char c;
    for (x=0,c=getchar();c<48;c=getchar());
    for (;c>47;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
}

void solve(){
	int a,b,c,d,e,f,g,h,i;
	a=read(),b=read(),d=read();
	if((b+d)%2!=0){
	    puts("-1");
	    return;
	} 
	i=(b+d)/2;
	if((a+i)%2!=0){
		puts("-1");
		return;
	}
	e=(a+i)/2;
	ll sum=a+e+i;
	g=sum-a-d;
	h=sum-b-e;
	f=sum-d-e;
	c=sum-a-b;
	printf("%d %d %d %d %d %d\n",c,e,f,g,h,i);
	
}

int main(){
	int t;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

3. Sequence I

考察:模拟

解法:
(1)
法一:全排列
因为数字个数最多8个,所以可以使用全排列。
枚举每种情况,求出按操作进行后的最小值。

代码如下:


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
const int N = 100;
int a[N];

inline int read(){
    int k=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
    while(ch>='0'&&ch<='9'){
		k=k*10+ch-'0';
		ch=getchar();
	}
    return k*f;
}

void rd(long long &x){
    char c;
    for (x=0,c=getchar();c<48;c=getchar());
    for (;c>47;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
}


void solve(){
	int n;
	scanf("%d",&n);
    memset(a,0,sizeof(a));
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    sort(a,a+n);
    int ans=INF;
    do{
    	int num=a[0];
    	for(int i=1;i<n;i++){
    		num-=a[i];
    		if(num<0) num*=-1;
		}
		ans=min(ans,num);
	}while(next_permutation(a,a+n));
	printf("%d\n",ans);
}

int main(){
	int t;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

(2)dfs

法二:dfs
递归边界为d==n,即已经合并完了。
此时更新ans=min(ans,abs(sum));
如果没有到达递归边界,继续dfs

代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N = 10;
#define INF 0x3f3f3f3f
int a[N],n,ans;

void dfs(int sum,int d){
	if(d==n){ 
		ans=min(ans,abs(sum));
		return;
	}
	dfs(sum+a[d],d+1);
	dfs(sum-a[d],d+1);
}

int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		memset(a,0,sizeof(a));
		ans=INF;
		scanf("%d",&n);
		for(int i=0;i<n;i++) scanf("%d",&a[i]);
		dfs(0,0);
		printf("%d\n",ans);
	}
	return 0;
}

(3)区间DP

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 20;
int a[N],n;
vector<int> v;

inline int read(){
    int k=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
    while(ch>='0'&&ch<='9'){
		k=k*10+ch-'0';
		ch=getchar();
	}
    return k*f;
}


inline void solve(){
	int n;
	n=read();
	set<int> dp[N][N];//自动去重并排序
	for(int i=1;i<=n;i++) {
		a[i]=read();
		dp[i][i].insert(a[i]);
	}
	if(n==2){
		printf("%d\n",abs(a[2]-a[1]));
		return;
	}
	//区间dp 
	for(int len=2;len<=n;len++){
		for(int i=1;i+len-1<=n;i++){
			int j=i+len-1;
			for(int k=i;k<j;k++){
				//依次算出两个相邻区间的差值并加入到集合中 
				for(auto x : dp[i][k]){
					for(auto y : dp[k+1][j]){
						v.push_back(abs(x-y));//加入到集合中 
					}
				}
			}
		    for(auto w : v) dp[i][j].insert(w);//将这段区间[i,j]的所有差值加入dp[i][j]种
		    v.clear();//记得清空
		}
	}
	int ans=*dp[1][n].begin();//区间1,n]中的最小值
	printf("%d\n",ans);
}

int main(){
	int t;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

4.Determinant

题意:给出2*2的矩阵的四个元素,求出x的范围使其对应的行列式的值大于0。

思路:
求出的分母为A,分子为B,A的正负号决定是小于还是大于,
x处在不同的位置情况不同。
(1)x在a位置,那么xd-bc>0 ,即x>bc/d;
(2) x在d位置,那么a
x-bc>0 , 即x>bc/a;
(3)x在c位置,那么ad-bx>0 即x<ad/b;
(4)x在b位置,那么a
d-xc>0,即x<ad/c;

Notice:
sscanf函数的运用:传送门

代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N = 100;
int n,aa,bb,cc,dd,A,B;
char a[N],b[N],c[N],d[N];

int gcd(int a,int b){
	return b==0 ? a : gcd(b,a%b);
}

int main(){
	scanf("%d",&n);
	while(n--){
		scanf("%s%s%s%s",a,b,c,d);
		sscanf(a,"%d",&aa);//读取里面的整数部分 
		sscanf(b,"%d",&bb);
		sscanf(c,"%d",&cc);
		sscanf(d,"%d",&dd);
		if(a[0]=='x') A=dd,B=bb*cc;
		if(d[0]=='x') A=aa,B=bb*cc;
		if(c[0]=='x') A=-bb,B=-aa*dd;
		if(b[0]=='x') A=-cc,B=-aa*dd;
		if(A==0&&B<0) puts("R");//必然大于0,实数集 
		if(A==0&&B>=0) puts("E");//小于0,矛盾,空集 
		if(A>0){ //如果最后结果是大于0的 
			int g=abs(gcd(A,B));//求最大公约数 
			A/=g;
			B/=g;
			cout<<"x>"<<B;//大于 
			if(A>1) cout<<"/"<<A;//如果分母为大于1的 
			cout<<endl;
		}
		if(A<0){//如果为负 
			int g=abs(gcd(A,B));
			A/=-g;
			B/=-g;
			cout<<"x<"<<B;//小于 
			if(A>1) cout<<"/"<<A;// 
			cout<<endl;
		}
	}
	return 0;
}

5.Lights and Robot

考察: 异或,模拟

思路:
用异或来改变灯的状态,分别用rcnt,ccnt,diagcnt来记录亮着的行数,列数,对角元素个数。
不管主对角线元素时,
ll ans=1llnn-1ll*(n-rcnt)(n-ccnt)-1llrcntccnt;
如果最后主对角线的状态是改变,即d=1,
那么再加上主对角线元素上亮着的灯的数目
ans+=n-2
diagcnt;

代码如下:

/*涉及开关问题,用异或 

*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
bool r[N],c[N];

inline int read(){
    int k=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
    while(ch>='0'&&ch<='9'){
		k=k*10+ch-'0';
		ch=getchar();
	}
    return k*f;
}


inline void solve(){
	int n,m,rcnt=0,ccnt=0,diagcnt=0;//rcnt记录亮着的行数,cnt记录亮着的列数,diagcnt记录亮着的对角线元素数 
	bool d=0;//标记主对角线是否被改变为亮着的 
	n=read(),m=read();
	for(int i=1;i<=n;i++) r[i]=c[i]=0;//最初都是关着的 
	while(m--){
		char s[10];
		scanf("%s",s);
		if(s[0]=='D') d^=1;//主对角线 
		else{
			int x;
			x=read();
			if(s[0]=='R'){
				rcnt+=r[x]?-1:1;//如果是亮着的就关,是关着的就打开 
				diagcnt+=r[x]^c[x]?-1:1;//对角线元素:如果是两者的即r[x]^c[x]=1,就关,否则,开 
				r[x]^=1;//改变这一行的状态 
			}
			else{
				ccnt+=c[x]?-1:1;
				diagcnt+=r[x]^c[x]?-1:1;//对角线 
				c[x]^=1;//改变这一列的状态 
			}
		}
		ll ans=1ll*n*n-1ll*(n-rcnt)*(n-ccnt)-1ll*rcnt*ccnt;//先不管主对角线元素时,开着的=总数-关着的
		//而关着的数目为:(n-rcnt)*(n-ccnt)+rcnt*ccnt 
		if(d) ans+=n-2*diagcnt;//对角线上亮着的元素个数:n-2*diagcnt 
		printf("%lld\n",ans);
	}
}

int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		solve();
	}
	return 0;
}

6.Lucky Numbers ABCD

考察:构造

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

inline void rd(long long &x){
    char c;
    for (x=0,c=getchar();c<48;c=getchar());
    for (;c>47;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
}

inline void solve(){
	ll n,ans;
	rd(n);
	ll l=1,r=1<<30;
	//二分 
	while(l<=r){
		ll mid=(l+r)>>1;
		if(1ll*mid*(mid+1)<n){
			ans=mid,l=mid+1;
		}
		else r=mid-1;
	}
	//构造,直接利用乘积格式相同 
	if(1ll*(ans+1)*(ans+1)>n){
		printf("%lld %lld %lld %lld\n",(ans-1)*ans,(ans-1)*(ans+1),ans*ans,ans*(ans+1));
		
	}
	else {
		printf("%lld %lld %lld %lld\n",(ans-1)*(ans+1),(ans-1)*(ans+2),ans*(ans+1),ans*(ans+2));
	}
}

int main(){
	int t;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值