Codeforces Round #675 (Div. 2)

A. Fence

签到题

  • 题设:给定三个代表三条边的值:a,b,c,求出任意一个能和这三条边构成一个四边形的长度d。
  • 思路:构成合法四边形的规则是任意三边和要绝对大于第四条边。
    输出a+b+c-1即可,注意范围,全用long long。
    因用int存a,b,c导致计算时数据溢出wa了一发,就临时想了个稍微绕弯但可行的思路,如下:
    因数据范围是三个1e9,为了防止溢出采用了保守方法。先计算a,b,c中较小两个值的和sum和a,b,c中最大值max,若这个sum已经比a,b,c中最大值max还大了,输出d=1即可,否则,令d=max-sum+1。

B. Nice Matrix

思维题

  • 题设:给定一个n×m大小的矩阵,每次可对其中任意一个位置的元素进行+1或者-1操作,问最少多少次操作能使这个矩阵,每一行每一列都回文(中心对称)。
  • 思路:
  1. 根据行列均回文可判断出每个元素和哪些位置的其他元素有关联,不难推算出,对于简单情况下的a[ i ][ j ],另外三个位置上的元素a[ i ][ m-j+1 ],a[ n-i+1 ][ j ],a[ n-i+1 ][ m-j+1 ]必须与其相等才符合条件。那特殊情况下,当每次遍历到行列的中间元素时,不难得出:
    列数为偶数,行数为奇数:只需要a[ i ][ j ] == a[ i ][ m-j+1 ]
    列数为奇数,行数为偶数:只需要a[ i ][ j ] == a[ n-i+1 ][ j ]
    列数为奇数,行数为奇数:不需要操作,a[ i ][ j ]无关联元素,可为任意值。

  2. 判断完哪些元素相互关联后,就需要通过操作使关联元素全部相等,即推算出最后这四个元素相等的特殊值X。

在这里插入图片描述
根据图辅助理解可知,四段红线权值即为需要的总操作数,那么只有当X属于a2—a3范围内时总操作数最少,注意:因为a2—a3范围内不一定包含(a1+a4)/2,这里简便化,取X值为a3(或a2)。
——AC代码:

#include<bits/stdc++.h>
#define ll long long
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define rep(i,s,e) for(int i=s;i<e;i++)
#define mem(a,n) memset(a, n ,sizeof a)
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const int INF= 0x3f3f3f3f;
priority_queue <int,vector<int>,less<int> > Q;
int a[110][110];
int find(int x1,int x2,int x3,int x4)
{
	int M=max(x1,max(x2,max(x3,x4)));
	if(x1==M)	return max(x2,max(x3,x4));
	if(x2==M)	return max(x1,max(x3,x4));
	if(x3==M)	return max(x1,max(x2,x4));
	if(x4==M)	return max(x1,max(x2,x3));
}
int main()
{
	IOS;
	int t,n,m;
	cin>>t;
	while(t--)
	{
		cin>>n>>m;
		rep(i,1,n+1)
			rep(j,1,m+1)
				cin>>a[i][j];
		ll ans=0;
		int midN=n/2+n%2;
		int midM=m/2+m%2;
		int a1,a2,a3,a4,M;
		for(int i=1;i<=midN;i++)
		{
			for(int j=1;j<=midM;j++)
			{
				//a1,a2,a3,a4;
				if(i==n-i+1 && j==m-j+1)
					continue;
				if(i==n-i+1)
				{
					ans+= abs(a[i][j]-a[i][m-j+1]);
					continue;
				}
				if(j==m-j+1)
				{
					ans+= abs(a[i][j]-a[n-i+1][j]);
					continue;
				}
				a1=a[i][j];
				a2=a[i][m-j+1];
				a3=a[n-i+1][j];
				a4=a[n-i+1][m-j+1];
				M=find(a1,a2,a3,a4);
				ans+= abs(a1-M)+ abs(a2-M)+ abs(a3-M)+ abs(a4-M);
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

C. Bargain

数论

  • 题设:输入一数n,1 <= n < (1010)5,可从这个总位数为len的数n中任意抽出 1~len-1 位连续的数字,抽完后(各个位上的数发生相应变化)前后两段聚拢变成一个新的数m,求出所有抽出情况m的总和,答案对 1e9+7 取模。
  • 思路:首先数n较大,且涉及到各个位上数字的变化,采用字符串进行读取和操作。这里我们令s[ i ] 表示第 i 位的数字,然后,对于抽出任意长度的连续数字,有两种情况:
  1. 抽出的数字全在这个数字的前面,即抽出后不会影响s[ i ]的位次,可简化问题为s[ i ]前的各个数字任意抽取有多少种情况,定义情况总数变量为lth,每个情况都要算上一次s[ i ]×它原始位次的倍数k。
  2. 抽出的数字全在这个数字的后面,此时就会对s[ i ]的位次产生影响,这里定义一个sum变量,表示每个数字在这种情况下,会在它的原始位次的后面出现多少次,每次加上s[ i ]× sum。这里对于这个sum的累加更新需要用到位次k。
    ——AC代码:
#include<bits/stdc++.h>
#define ll long long
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define rep(i,s,e) for(int i=s;i<e;i++)
#define mem(a,n) memset(a, n ,sizeof a)
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const int INF= 0x3f3f3f3f;
priority_queue <int,vector<int>,less<int> > Q;
const int mod= 1e9+7;

int main()
{
	IOS;
	string s;
	cin >> s;
	ll len=s.size();
	reverse(s.begin(),s.end());//反转整个字符串
	
	ll ans=0, sum=0, k=1;
	for(int i=0;i<len;i++)
	{
		ll shu= s[i]-'0';
		ll lth= ( (len-i-1)*(len-i)/2 ) % mod;
		//lth表示当前shu在各个子串中相对位次不变时 出现的次数 
		ans = (ans + shu * lth * k) % mod;
		//sum计算的是shu在各个子串中相对位次变化时 出现的次数 
		ans = (ans + shu * sum) % mod;
		sum = (sum + k*(i+1)) % mod;
		k = k*10 % mod;
	}
	cout<<ans;
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_45928596

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值