1001 A + B = C
考虑最终答案的形式(列竖式),因为两个数相加最多只会进一位,所以C要么和A/B对齐,要么往前多一位,暴力判断四种情况即可
1006 Final Exam
本题的难点在于读题。。
首先题目的直观理解应该是,我给出一种复习方法,那么不管题目怎么分配,我都能做出至少k题,换句话说,我的方案必须可以应付所有的出题情况
那么我们可以反方向考虑,如何构造一种情况让我做不到k道题?也就是说怎么卡掉我的复习方案?
假设每道题的复习时间是
t
i
t_i
ti,一个最暴力的方法就是每道题的分数都是
t
i
t_i
ti
那么如果分数不够用怎么办?注意我们可以让其中
k
−
1
k-1
k−1道题的分数变少(即我可以让你做出
k
−
1
k-1
k−1道题),那么显然要让复习分数最多的
k
−
1
k-1
k−1道题分数变少,当然了肯定是变成0
那么如果剩下的分数小于等于m,那么我们就构造出了一种题目分数方案卡掉我的复习方案,否则我的方案就是一种合法解
从这种方法去想,我们只需要让最少的
n
−
k
+
1
n-k+1
n−k+1门课的复习时间总和大于
m
m
m就好了,平均分配即可
#include<bits/stdc++.h>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int T,n,m,k,t;
long long res1,res2;
int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%d%d%d",&n,&m,&k);
t = m / (n - k + 1) + 1;
res1 = 1ll * t * (k - 1) + (m + 1);
cout<<res1<<endl;
}
return 0;
}
1010 Just Repeat
如果一种花色的牌只有一个人拥有,那么直接计入答案就好,因为这种花色对策略没有影响
然后考虑两个人都有的花色怎么打
显然不能只考虑自己有多少牌,也要考虑对方有多少牌,因为你出一张牌不但能保证自己能出这个花色,还能封住对面的花色
考虑一个花色,对面有
x
x
x张,我有
y
y
y张,那么如果对面出,收益是
−
x
-x
−x张(表示能让对面过
x
x
x张牌),我出收益是
y
y
y张,所以我出这张牌的收益应该是
x
+
y
x+y
x+y
所以我们只需要按照某种花色的总数进行排序,然后轮流取就好
至于做法的正确性证明。。我也不清楚,因为也是猜的结论2333
后来想了一个奇奇怪怪的证明方法:
假设有一种花色的排列顺序,不是按照总数进行排序,并且答案最优
显然必定存在一对相邻的逆序对,不妨设:
花色1 | 花色2 | |
---|---|---|
先手 | A A A | B B B |
后手 | C C C | D D D |
如果按照正常的取法应该是先手拿
A
A
A,后手拿
D
D
D,先手可以多出
A
−
D
A-D
A−D张(带符号)
如果我们换一种取法,先手拿
B
B
B,后手拿
C
C
C,那么先手可以多出
B
−
C
B-C
B−C张
由于这是最优取法,所以肯定有
A
−
D
>
=
B
−
C
A-D>=B-C
A−D>=B−C,整理得
A
+
C
>
=
B
+
D
A+C>=B+D
A+C>=B+D
这和题设“逆序对”不符合,故假设不成立
所以当按照总数降序的顺序取最优
#include<bits/stdc++.h>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define N 1000005
using namespace std;
struct node{int x,y;} g[N*2];
int T,n,m,p,i,mod,k,res1,res2,num;
int a[N],b[N],f[N*2],x[N],y[N];
unsigned long long k1, k2;
unsigned long long rng()
{
unsigned long long k3 = k1, k4 = k2;
k1 = k4;
k3 ^= k3 << 23;
k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
return k2 + k4;
}
const cmp(const node &a,const node &b) {return a.x+a.y > b.x+b.y;}
int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%d%d%d",&n,&m,&p);
if (p == 1)
{
fo(i,1,n) scanf("%d",&a[i]);
fo(i,1,m) scanf("%d",&b[i]);
} else
{
scanf("%llu%llu%d",&k1,&k2,&mod);
fo(i,1,n) a[i] = (int)(rng() % (unsigned long long)mod);
scanf("%llu%llu%d",&k1,&k2,&mod);
fo(i,1,m) b[i] = (int)(rng() % (unsigned long long)mod);
}
//fo(i,1,n) cout<<a[i]<<" "; cout<<endl;
//fo(i,1,m) cout<<b[i]<<" "; cout<<endl;
k = 0;
fo(i,1,n) f[++k] = a[i];
fo(i,1,m) f[++k] = b[i];
sort(f+1,f+n+m+1);
k = unique(f+1,f+n+m+1) - (f+1);
fo(i,1,n) a[i] = lower_bound(f+1,f+k+1,a[i]) - f;
fo(i,1,m) b[i] = lower_bound(f+1,f+k+1,b[i]) - f;
res1 = res2 = 0;
fo(i,1,n) x[a[i]]++;
fo(i,1,m) y[b[i]]++;
num = 0;
fo(i,1,k)
if (x[i] == 0 && y[i] != 0)
{
res2 += y[i];
} else
if (x[i] != 0 && y[i] == 0)
{
res1 += x[i];
} else
{
num++; g[num].x = x[i]; g[num].y = y[i];
}
sort(g+1,g+num+1,cmp);
fo(i,1,num)
{
if (i % 2 == 1) res1 += g[i].x; else res2 += g[i].y;
}
if (res1 > res2) printf("Cuber QQ\n"); else printf("Quber CC\n");
fo(i,1,n) x[a[i]]--;
fo(i,1,m) y[b[i]]--;
}
return 0;
}
1011 Kejin Player
经典的概率
d
p
dp
dp
设
f
[
i
]
f[i]
f[i]表示升到
i
i
i级的期望花费,那么这个期望值应该是满足区间可加性的,即从
i
i
i级升到
j
j
j级的期望花费应该是
f
[
i
]
−
f
[
j
]
f[i]-f[j]
f[i]−f[j](注意这里不是
j
−
1
j-1
j−1)
分别考虑升级的时候,成功和失败的花费
那么显然有
f
[
i
+
1
]
=
f
[
i
]
+
p
i
(
a
i
)
+
(
1
−
p
i
)
(
a
i
+
f
[
i
+
1
]
−
f
[
x
]
)
f[i+1]=f[i]+p_i(a_i)+(1-p_i)(a_i+f[i+1]-f[x])
f[i+1]=f[i]+pi(ai)+(1−pi)(ai+f[i+1]−f[x])
成功了就直接升级,失败了就要从
x
i
x_i
xi升级
移项之后
O
(
n
)
O(n)
O(n)预处理即可