Codeforces round341 div2

Codeforces round341 div2

A:给出n个数,要求从中选数使得和最大且和为偶数;

       统计所有数之和,若奇数个数 Mod 2 == 1,答案减去最小的那个奇数。

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>
using namespace std;
int n,num = 0;
long long a,Ans = 0,minx = 1e18;
int main() {
	scanf("%d",&n);
	for(int i = 1;i <= n;i ++)
	{
		scanf("%I64d",&a);Ans += a;
		if(a % 2 == 1) num ++,minx = min(minx,a);
	}
	Ans -= (num % 2 == 0) ? 0 : minx;
	cout<<Ans;
}


B:给出1000*1000 矩阵上的一些点,问有多少对点在同一条对角线上。

       我们把所有的点化成直线解析式的形式,用桶装一下,最后统计答案就可以了。

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>
using namespace std;
int n,a,b;
long long Ans = 0,N[3010][2],M[3010][2];
int main() {
	scanf("%d",&n);
	for(int i = 1;i <= n;i ++)
	{
		scanf("%d%d",&a,&b);
		int x = b - a;
		if(x < 0) N[-1 * x][0] ++;
		else N[x][1] ++;
		int y = b + a;
		if(y < 0) M[-1 * y][0] ++;
		else M[y][1] ++;
	}
	for(int i = 0;i <= 2005;i ++)
	{
		for(int j = 0;j <= 1;j ++)
		{
			Ans += (N[i][j] * (N[i][j] - 1)) / 2;
			Ans += (M[i][j] * (M[i][j] - 1)) / 2;
		}
	}
	cout<<Ans;
	return 0;
}


C:给出n个数对(l[i],r[i]),以及一个质数p,现在n个数,每个数i的值是一个l[i]到r[i]之间的随机数,(这n个数构成了一个环),每当有val[i]* val[i+1] 或者val[i] *val[i-1]被p整除,那么就会有2000的代价,求最后的代价期望。

       因为p是质数,这道题简单了许多。

我们对于每个i统计它的取值范围内有多少个p的倍数,设为num[i],那么4000*num[i]*All除以K[i]就是他对答案的贡献(All是所有数取值的总方案数,K[i]是i取值的方案数(即r[i]-l[i]+1),乘4000是因为对左右都有贡献。),但是要除去左右两边都是p的倍数的情况,所以再减去2000*num[i]*num[i+1]*All除以K[i]再除以K[i+1],只考虑往后相同的情况,不然会多减(其实就是一个简单的容斥),然后最后把答案除以All就是期望辣,但是All是一个很大的数,我们发现之前乘了All,之后又除了,所以说直接约掉就行了。

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>
#define d(x) double(x)
using namespace std;
long long n,p,A[200010],B[200010],num[200010];
double Ans = 0,tim = 1;
int main() {
	cin>>n>>p;
	for(int i = 1;i <= n;i ++) 
		scanf("%I64d%I64d",&A[i],&B[i]);
	A[n + 1] = A[1];
	B[n + 1] = B[1];
	A[0] = A[n];
	B[0] = B[n];
	for(int i = 0;i <= n + 1;i ++) 
		num[i] = B[i] / p - (A[i] - 1) / p;
	for(int i = 1;i <= n;i ++)
	{
		Ans += d(4000) * d(num[i]) / d(B[i] - A[i] + 1);
		Ans -= d(2000) * d(num[i]) * d(num[i + 1]) / d(B[i] - A[i] + 1) / d(B[i + 1] - A[i + 1] + 1);
 	}
	printf("%0.10f",Ans);
	return 0;
}


D:给出12个对于x,y,z的函数f[i](x,y,z),询问其中的最大值,输出那个函数。

       (其中函数的运算都是幂运算,比如x^y^z,结果可能很大,x,y,z<=200)。

       首先直接使用pow函数是会爆精度的,我们考虑用其他方式来减小答案却又不影响比较,于是想到了log(这个经常用到,要记住),x^y^z就变成了log(x)*pow(y,z)这样以后精度就没有太大问题了,但是还是要开long double,不然狂wa(python大法好)。

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>
using namespace std;
long double Ans = -1 * 1e300,x,y,z,A[14];
int p;
int main() {
	cin>>x>>y>>z;
	A[1] = pow(y,z) * log(x);
	A[2] = pow(z,y) * log(x);
	A[3] = A[4] = z * y * log(x);
	A[5] = pow(x,z) * log(y);
	A[6] = pow(z,x) * log(y);
	A[7] = A[8] = x * z * log(y);
	A[9] = pow(x,y) * log(z);
	A[10] = pow(y,x) * log(z);
	A[11] = A[12] = x * y * log(z);
	for(int i = 1;i <= 12;i ++)
	{
		if(A[i] > Ans)
		{
			Ans = A[i];
			p = i;
		}
	}
	if(p == 1) cout<<"x^y^z";
	if(p == 2) cout<<"x^z^y";
	if(p == 3) cout<<"(x^y)^z";
	if(p == 4) cout<<"(x^z)^y";
	if(p == 5) cout<<"y^x^z";
	if(p == 6) cout<<"y^z^x";
	if(p == 7) cout<<"(y^x)^z";
	if(p == 8) cout<<"(y^z)^x";
	if(p == 9) cout<<"z^x^y";
	if(p == 10) cout<<"z^y^x";
	if(p == 11) cout<<"(z^x)^y";
	if(p == 12) cout<<"(z^y)^x";
	return 0;
	
}


E:给出b个序列A(b个序列都是一样的),你可以从中选b个数(一个序列选一个),然后把这b个数排成一个数字(比如你选了1,2,答案就是12),再Mod给定的数x,问有多少种选法使得最后的答案是k。(序列中的数<=9,k<=100,x<=100,k<x,b<=10^9,一个序列中不同位置的相同数算两种方案)。

       首先想到转移方程:

       F[i][c* 10 + num] += F[i-1][c] (当前选的是num这个数字)。

       所以就可以矩阵乘法了,先预处理出数字i在之前的余数是c的情况下会转移到的状态(即(c * 10 + i)Mod p),然后矩阵中Dp[i][(c * 10 + i)Mod p] + 1就行了。

       裸矩乘。

 

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>
#define Mod 1000000007
using namespace std;
int n,b,k,x,p,a;
struct Matrix {
	long long val[101][101];
	Matrix () {memset(val,0,sizeof(val));}
	friend Matrix operator *(Matrix x,Matrix y) {
		Matrix Ans;
		for(int i = 0;i < p;i ++)
			for(int j = 0;j < p;j ++)
				for(int k = 0;k < p;k ++)
				{
					Ans.val[i][j] += x.val[i][k] * y.val[k][j];
					Ans.val[i][j] %= Mod;
				}
		return Ans;
	} 
	friend Matrix operator^(Matrix X,int Y) {
		Matrix Ans;
		for(int I = 0;I <= p - 1;I ++)
		    Ans.val[I][I] = 1;
		while(Y > 0) 
		{
			if(Y % 2 == 1) Ans = Ans * X;
			X = X * X;
			Y = Y / 2;
		}
		return Ans;
	}
}A,B;
int main() {
	scanf("%d%d%d%d",&n,&b,&k,&p);
	for(int i = 1;i <= n;i ++)
	{
		scanf("%d",&a);
		for(int j = 0;j < p;j ++)
		{
			B.val[j][(j * 10 + a) % p] ++;
		}
	}
	A.val[0][0] = 1;
	A = A * (B ^ b);
	printf("%I64d",A.val[0][k]);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值