Codeforces Round 341 div2
题目链接:
通过数:3(一题被叉一题未看懂)
Standing:310/5929
Rating change: 1862-1869
比赛总结:
题目都属于可以理解可以做的范围,原来以为要变色了……
A:
所有数任意选,求最大的和且和为偶数的值。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
#define LL long long
const int MAXN = 100000 + 5;
LL a[MAXN];
int main()
{
int n;
while(scanf("%d", &n) != EOF){
int cnt = 0;
LL sum = 0;
for(int i = 0 ; i < n ; i++){
LL u;
scanf("%I64d", &u);
if(u % 2 == 1) a[cnt++] = u;
sum += u;
}
if(sum % 2 == 0) printf("%I64d\n", sum);
else{
sort(a, a + cnt);
printf("%I64d\n", sum - a[0]);
}
}
return 0;
}
B:
坐标,发现就是y=x+b和y=-x+b上,所以直接换了个坐标系。
好像有更复杂的写法,然而不想补了
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
#define LL long long
const int MAXN = 4000 + 100;
int c1[MAXN], c2[MAXN];
int main()
{
int n;
while(scanf("%d", &n) != EOF){
memset(c1, 0, sizeof(c1));
memset(c2, 0, sizeof(c2));
LL ans = 0;
for(int i = 0 ; i < n ; i++){
int x, y;
scanf("%d%d", &x, &y);
int u = x - y + 1000;
int v = x + y + 1000;
ans += c1[u]; c1[u]++;
ans += c2[v]; c2[v]++;
}
printf("%I64d\n", ans);
}
return 0;
}
C:
刚开始没看懂题,看懂后秒过了。求相邻一对取数能取到p的倍数的概率,这还用想吗
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 100000 + 5;
int l[MAXN], r[MAXN];
double lv[MAXN];
double dp[MAXN][3];
int n, p;
double cal(int i)
{
return 1 - (1 - lv[i - 1]) * (1 - lv[i]) ;
}
int main()
{
while(scanf("%d%d", &n, &p) != EOF){
for(int i = 1 ; i <= n ; i++){
scanf("%d%d", &l[i], &r[i]);
int u1 = l[i] / p, v1 = l[i] % p;
int u2 = r[i] / p, v2 = r[i] % p;
int temp = u2 - u1;
if(v1 == 0) temp++;
lv[i] = 1.0 * temp / (r[i] - l[i] + 1);
}
l[0] = l[n], r[0] = r[n]; lv[0] = lv[n];
l[n + 1] = l[1], r[n + 1] = r[1]; lv[n + 1] = lv[1];
// for(int i = 0 ; i <= n + 1 ; i++) printf("lv[%d] = %f\n", i, lv[i]);
double ans = 0;
for(int i = 1 ; i <= n ; i++){
ans += cal(i) * 2000;
// printf("cal[%d] = %f\n", i, cal(i));
}
// memset(dp, 0, sizeof(dp));
// for(int i = 1 ; i <= n + 1; i++){
// if(i == 1){
// dp[i][0] = (1 - lv[i]);
// dp[i][1] = lv[i];
// }
// else{
// dp[i][0] = (1 - lv[i]) * (dp[i - 1][1]);
// dp[i][1] = lv[i] * (dp[i - 1][1] + dp[i - 1][0]);
// }
// printf("dp[%d][0] = %f, dp[%d][1] = %f\n", i, dp[i][0], i, dp[i][1]);
// }
// double ans = (dp[n + 1][0] + dp[n + 1][1]) * 1000 * n;
printf("%.6f\n", ans);
}
return 0;
}
D:
因为之前写过一个处理这种大数的题,所以得意忘形的开loglog处理就没管了……然而忘记了对数的性质。
笨办法是分类讨论,水办法是long double。
看到一种神做法,把数看成实数,然后排序……贴一下
转侵删
If x > 1, then log(log(x)) is an increasing function, and if x < 1, thenreal(log(log(x))) is a decreasing function, because taking a logarithm of a negative number results in something like this:log( - x) = log( - 1 * x) = log( - 1) + logx = iπ + log(x). (Assuming log(x) is done in base e) Therefore, to compare two numbers by their loglog, you can do something like this:
bool compare (complex x, complex y) {
if (imag(x) == 0 and imag(y) == 0)
return real(x) > real(y);
else if (imag(x) != 0 and imag(y) == 0)
return false;
else if (imag(x) == 0 and imag(y) != 0)
return true;
else if (imag(x) != 0 and imag(y) != 0)
return real(x) < real(y);}
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
#define inf (1000000007)
double a[20];
double cal1(double x, double y, double z)
{
double ans;
ans = z * log(y) + log(log(x));
// printf("x = %f, y = %f, z = %f\n");
// printf("first part = %f\nsecond part = %f\n", z * log(y), log(log(x)));
// system("pause");
// printf("ans = %f\n", ans);
return ans;
}
double cal2(double x, double y, double z)
{
double ans;
ans = log(y) + log(z) + log(log(x));
return ans;
}
int solve(double x, double y, double z)
{
for(int i = 1 ; i <= 12 ; i++) a[i] = -inf;
if(x <= 1 && y <= 1 && z <= 1){
double xx = 1.0 / x, yy = 1.0 / y, zz = 1.0 / z;
if(xx != 1){
a[1] = cal1(xx, y, z);
a[2] = cal1(xx, z, y);
a[3] = cal2(xx, y, z);
a[4] = cal2(xx, z, y);
}
if(yy != 1){
a[5] = cal1(yy, x, z);
a[6] = cal1(yy, z, x);
a[7] = cal2(yy, x, z);
a[8] = cal2(yy, z, x);
}
if(zz != 1){
a[9] = cal1(zz, x, y);
a[10] = cal1(zz, y, x);
a[11] = cal2(zz, x, y);
a[12] = cal2(zz, y, x);
}
int re = 1;
double mmax = a[1];
for(int i = 1 ; i <= 12 ; i++){
if(a[i] < mmax) mmax = a[i], re = i;
}
return re;
}
else{
if(x > 1){
a[1] = cal1(x, y, z);
a[2] = cal1(x, z, y);
a[3] = cal2(x, y, z);
a[4] = cal2(x, z, y);
}
if(y > 1){
a[5] = cal1(y, x, z);
a[6] = cal1(y, z, x);
a[7] = cal2(y, x, z);
a[8] = cal2(y, z, x);
}
if(z > 1){
a[9] = cal1(z, x, y);
a[10] = cal1(z, y, x);
a[11] = cal2(z, x, y);
a[12] = cal2(z, y, x);
}
}
// for(int i = 1 ; i <= 12 ; i++)
// printf("%f\n", a[i]);
// printf("\n");
int re = 1;
double mmax = a[1];
for(int i = 1 ; i <= 12 ; i++){
if(a[i] > mmax) mmax = a[i], re = i;
}
return re;
}
int out[5];
void print(int mark)
{
if(mark == 1) printf("x^y^z\n");
if(mark == 2) printf("x^z^y\n");
if(mark == 3) printf("(x^y)^z\n");
if(mark == 4) printf("(x^z)^y\n");
if(mark == 5) printf("y^x^z\n");
if(mark == 6) printf("y^z^x\n");
if(mark == 7) printf("(y^x)^z\n");
if(mark == 8) printf("(y^z)^x\n");
if(mark == 9) printf("z^x^y\n");
if(mark == 10) printf("z^y^x\n");
if(mark == 11) printf("(z^x)^y\n");
if(mark == 12) printf("(z^y)^x\n");
}
int main()
{
// printf("log(3.4) = %f, loglog(1.1) = %f\n", log(3.4), log(log(1.1)));
double x, y, z;
while(cin >> x >> y >> z){
// x *= 10, y *= 10, z *= 10;
// x *= 1000, y *= 1000, z *= 1000;
int mark = solve(x, y, z);
print(mark);
}
// }
return 0;
}
E:
这题改了一天……
题目意思说凑一个b位的数,要求它mod(x)==k。问有几种凑法。
首先按照数位dp思想。设dp[i][j]表示i位余数为j有多少种情况。然后发现这是一个矩阵快速幂,因为dp[i]可以由dp[i-1]得到。
然而那个矩阵怎么表示?因为乘式表示位dp[i-1]*T=dp[i],想到半夜得到的结果是T[i][j]表示当前余数为i、新添加j时得到余数为j的矩阵。T的初始化见代码,解释的意思是刚开始只有0位时,余数不定。然后由于dp[0] = {1,0,0,…0},故输出T[0][k]即可。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
#define LL long long
#define mod (1000000007)
const int MAXN = 100 + 5;
struct Matrix
{
LL a[MAXN][MAXN];
int len;
Matrix(){memset(a, 0, sizeof(a));}
void init(int _len){
len = _len;
for(int i = 0 ; i < len ; i++){
for(int j = 0 ; j < len ; j++){
if(i == j) a[i][j] = 1;
else a[i][j] = 0;
}
}
}
Matrix operator + (const Matrix &rbs)const{
Matrix res;
res.len = len;
for(int i = 0 ; i < len ; i++)
for(int j = 0 ; j < len ; j++) res.a[i][j] = (a[i][j] + rbs.a[i][j]) % mod;
return res;
}
Matrix operator * (const Matrix &rbs)const{
Matrix res;
res.len = len;
for(int i = 0 ; i < len ; i++){
for(int k = 0 ; k < len ; k++){
for(int j = 0 ; j < len ; j++)
res.a[i][j] = (res.a[i][j] + a[i][k] * rbs.a[k][j]) % mod;
}
}
return res;
}
void print(){
for(int i = 0 ; i < len ; i++){
for(int j = 0 ; j < len ; j++) printf("%I64d ", a[i][j]);
printf("\n");
}
}
};
Matrix ppow(Matrix u, int b)
{
Matrix ans;
ans.init(u.len);
for(int i = b ; i ; i >>= 1){
if(i & 1) ans = (ans * u);
u = (u * u);
// ans.print();
// printf("\n");
// u.print();
// system("pause");
}
return ans;
}
int n, b, k, x;
LL g[MAXN];
LL out[MAXN];
int main()
{
while(scanf("%d%d%d%d", &n, &b, &k, &x) != EOF){
memset(g, 0, sizeof(g));
int u;
while(n--){
scanf("%d", &u);
g[u % x]++;
}
Matrix temp;
temp.len = x;
for(int i = 0 ; i < x ; i++){
for(int j = 0 ; j < x ; j++){
temp.a[i][(10 * i + j) % x] = g[j];
}
}
// temp.print();
// system("pause");
// for(int i = 0 ; i < x ; i++){
// for(int j = 0 ; j < x ; j++) printf("%I64d ", temp.a[i][j]);
// printf("\n");
// }
temp = ppow(temp, b);
// temp.print();
// LL ans = 0;
// for(int i = 0 ; i < x ; i++) ans = (ans + temp.a[k][i]) % mod;
// printf("%I64d\n", ans);
// for(int i = 0 ; i < x ; i++){
// for(int j = 0 ; j < x ; j++) printf("%I64d ", temp.a[i][j]);
// printf("\n");
// }
// memset(out, 0, sizeof(out));
// for(int i = 0 ; i < x ; i++) for(int j = 0 ; j < x ; j++) out[i] = (out[i] + g[j] * temp.a[i][j]) % mod;
// for(int i = 0 ; i < x ; i++) printf("%I64d ", out[i]);
// printf("\n");
printf("%I64d\n", temp.a[k][0]);
}
return 0;
}