A. Berland Poker(简单情况讨论)
分析
- 主要的思路就是,先计算出平均每个手中手中的牌的数量ct,这个时候我们考虑,接下来要先让分数尽可能的大,就应该让 尽可能多的的joker牌在一个人的手中,那么我们就分类讨论
- 如果m<=ctl,就把m张牌都给一个人
- 如果m>ct,就把ct张牌给一个人,然后剩下的牌 平均分配就行了
代码
#include
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair
#define PIR pair
#define INF 0x3f3f3f3f
#define mod 998244353
const int mxn = 2e5 + 10;
int ar[mxn];
int main()
{
int T;
scanf("%d", &T);
while(T --)
{
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
int ct = n / k;
int mx = min(ct, m);
int sr = m - mx;
k --;
int ans = mx - ceil((db)sr / k);
printf("%d\n", ans);
}
return 0;
}
B. New Theatre Square(模拟)
分析
- 给我们一个n*m的方格区域,这个放个区域内 , ∗ * ∗表示已经铺过砖了,而’.'表示还没有铺过砖,
- 现在给我们两种规格:1x1的砖、1x2的砖,花费的代价对应为 a、b,注意这两种砖只能 横向铺方格区域,不能竖着铺
- 问将方格中的 空白区域铺满最少需要的代价是多少?
- 首先我们对于1x2的砖话费的最少代价为 b = min(b, 2*a),
- 之后就是在某一行中,如果某个 连续空白格的数量是偶数的话,我们全部用1X2的砖去铺,否则用一个1x1的砖之后剩下的都用2x2的砖去铺
- 模拟遍历一遍,统计总费用
代码
#include
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair
#define PIR pair
#define INF 0x3f3f3f3f
#define mod 998244353
const int mxn = 1e3 + 10;
char ar[mxn][mxn];
int main()
{
int T;
scanf("%d", &T);
while(T --)
{
int n, m, a, b;
scanf("%d %d %d %d", &n, &m, &a, &b);
b = min(2 * a, b);
for(int i = 1; i <= n; i ++)
{
scanf("%s", ar[i] + 1);
ar[i][0] = '*';
ar[i][m + 1] = '*';
}
int sum = 0;
for(int i = 1; i <= n; i ++)
{
int lst = m;
int pre = m;
for( ; pre >= 0; pre -- )
{
if(ar[i][pre] == '*')
{
sum += (lst - pre) / 2 * b + (lst - pre) % 2 * a;
lst = pre - 1;
}
}
}
printf("%d\n", sum);
}
return 0;
}
C. Mixing Water(二分/三分/数学 )
分析
- 给我们一个空桶,我们可以向其中 倒入 x杯热水,之后可以选择向其中倒入 (x-1)或者 x 杯凉水 , 热水的温度为 h,冷水的温度为c,
- 倒入桶中的温度为水的平均温度
这一题并不难,可惜当时题意读错了,这里说一下三分的做法
- 我们先讨论如果 h+c>=2*t的话,那么我们就只需要 1杯热水和1杯凉水
- 否则的话,我们就一定需要x+1杯热水,x杯凉水,但是x的具体值我们不知道,但是我们大致知道,随着x的增加应该是一个 抛物线形状的变化曲线,所以我们可以用三分去枚举x,
代码
#include
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair
#define PIR pair
#define INF 0x3f3f3f3f
#define mod 998244353
ll h, c, t;
db check(db a, db b)
{
return abs((a * h + b * c) / (a + b) - t);
}
int main()
{
int T;
scanf("%d", &T);
while(T --)
{
scanf("%lld %lld %lld", &h, &c, &t);
if(h + c >= 2 * t)
{
printf("2\n");
}
else
{
ll l = 0, r = INF, lm, rm;
while(l < r)
{
lm = l + (r - l) / 3;
rm = r - (r - l) / 3;
if(check(lm + 1, lm) <= check(rm + 1, rm))
r = rm - 1;
else
l = lm + 1;
}
printf("%lld\n", 2 * l + 1LL);
}
}
return 0;
}
D. Yet Another Yet Another Task(思维+方法)
分析
- 给我们一个序列ar[i],让我们在这个序列中选择连续的一个区间,我们得到分数=这个区间中所有的元素和 - 这个区间中元素的最大值,问通过可以的选择区间我们能够得到的最大的分数是多少?
- 注意到序列元素的值在 [ − 30 , 30 ] [-30,30] [−30,30]之间,这肯定是有用的一点,
- 而我们主要思路就是通过枚举区间元素的最大值x,这样一旦 在遍历数组的时候遇到ar[i]>x,那么当前的区间端就要从i这个位置断开,之后从i+1位置开始下一个连续区间的,
- 其次是我们在遍历寻找符合题意的区间段的时候,我们要在每一个位置都要维护区间最大和 即: a n s = m a x ( a n s , s u m ) ans=max(ans,sum) ans=max(ans,sum)
代码
#include
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair
#define PIR pair
#define INF 0x3f3f3f3f
#define mod 998244353
const int mxn = 1e5 + 100;
int ar[mxn];
int main()
{
int n;
scanf("%d\n", &n);
for(int i = 1; i <= n; i ++)
scanf("%d\n", &ar[i]);
int ans = 0;
for(int i = 1; i <= 30; i ++)
{
int sum = 0;
for(int j = 1; j <= n; j ++)
{
if(ar[j] > i)
sum = 0;
else
{
sum += ar[j];
if(sum < 0) sum = 0;
ans = max(ans, sum - i);
}
}
}
printf("%d\n", ans);
return 0;
}
E. Modular Stability(数论)
分析
- 给我们一个由n个数组成序列S={1,2,3…n},现在我们 我可以从中任意选择k个数按从小到大的顺序组成一个新的序列ar,
- 如果存在正整数x令: x % a r [ 1 ] % a r [ 2 ] . . . % a r [ k ] = = ~x\%ar[1]\%ar[2]...\%ar[k]== x%ar[1]%ar[2]...%ar[k]== x按任意顺序区域ar中的元素之后的值,则ar为稳定数组
- 问有多少选择方案,使产生的 ar 为稳定数组
- 易得上式的取值结果,有ar中最小的值决定,我设这个最小值为ar1
- 我们设 x = n ∗ a r 1 + m x=n*ar1+m x=n∗ar1+m,那么m就是表达式最终的取余的结果,接着我们推出 ( n 1 ∗ a 1 + m ) % a r [ i ] = ( n 2 ∗ a r 1 + m ) (n1 * a1+m)\%ar[i]=(n2*ar1+m) (n1∗a1+m)%ar[i]=(n2∗ar1+m),我可以得出ar中任意一个数都要是ar1的倍数,这个样就能保证任意的取余顺序都能保证得到的取余结果相同了,
- 又因为ar中元素各不相同,所以我们只要枚举 ar1的值,剩下的就是在n/ar[i]-1个ar1的倍数中 选择k个就行了,最终总方案数就是 ∑ i = 1 n C n / i − 1 k − 1 \sum_{i=1}^nC_{n/i-1}^{k-1} ∑i=1nCn/i−1k−1.