CF EDU8
A. Tennis Tournament
思路
首先对于毛巾, 每个选手p条, n个选手, 共n * p 条
对于水, 首先, 每场选手b瓶, 裁判1瓶, 共2b+1瓶
然后水还要算场数。
对于每轮有k个人, 那么就有
⌊
k
2
⌋
\lfloor \frac{k}{2} \rfloor
⌊2k⌋ 场 比赛, 相应的, 也会有这么些人被淘汰。
最后判断剩一个人
代码
#include<bits/stdc++.h>
using namespace std;
int n, b, p;
int main()
{
cin >> n >> b >> p;
int m = n;
int cnt = 0;
while(n >= 2)
{
int k = n / 2;
cnt += k;
n -= k;
}
cout << cnt * (2 * b + 1) << " " << m * p << endl;
return 0;
}
B. New Skateboard
思路
因为25 * 4 == 100;
所以只要一个数, 后两位为0时都能被整除。
只需要判断后两位即可
如果后两位能被成功整除的话, 无论与前面哪个组合都ok。
再加上一位整除4的。
代码
/* CF 628B New Skateboard --- 水题 */
#include <cstdio>
#include <cstring>
char s[300005];
int main()
{
while (scanf("%s", s) == 1){
long long len = strlen(s);
long long cnt = 0;
long long num;
//处理前第一个数
num = s[0] - '0';
if (num % 4 == 0){
++cnt;
}
for (long long i = 1; i < len; ++i){
//判断当前位以及往前的位
num = s[i] - '0';
if (num % 4 == 0){
++cnt;
}
num = (s[i - 1] - '0') * 10 + s[i] - '0';
if (num % 4 == 0){
cnt += i;
}
}
printf("%lld\n", cnt);
}
return 0;
}
C. Bear and String Distance
思路
简单贪心, 对于每一个k, 首先我们让当前跳到‘a’, 和 ’z’, 尽量dist最大化。
如果有一次跳, 超过k了, 在不断调整。
如果跳完了还不够k, 输出‘-1’
代码
#include<bits/stdc++.h>
using namespace std;
string s;
int n, k;
char ans[100010];
bool flag;
int main()
{
cin >> n >> k;
cin >> s;
if(k == 0)
{
cout << s << endl;
return 0;
}
int pans = 0;
for(int i = 0; i < s.size(); i++)
{
if(flag)
{
ans[i] = s[i];
continue;
}
char c = s[i];
int d1 = c - 'a';
int d2 = 'z' - c;
if(d1 <= d2 && k >= d2)
{
ans[i] = 'z';
k -= d2;
}
else if(d1 > d2 && k >= d1)
{
ans[i] = 'a';
k -= d1;
}
else
{
if(d1 >= k)
{
ans[i] = s[i] - k;
k = 0;
}
else
{
ans[i] = s[i] + k;
k = 0;
}
}
if(k == 0)
{
flag = true;
}
}
if(!flag)
{
printf("-1\n");
}
else
{
for(int i = 0; i < s.size(); i++)
{
printf("%c", ans[i]);
}
cout << endl;
}
return 0;
}
DALAO的优化更简洁
#include <bits/stdc++.h>
using namespace std;
#define FOR(i, j, k) for(int i=(j); i<=(k); i++)
#define FFOR(i, j, k) for(int i=(j); i<(k); i++)
#define DFOR(i, j, k) for(int i=(j); i>=(k); i--)
#define bug(x) cerr<<#x<<" = "<<(x)<<'\n'
#define pb push_back
#define mp make_pair
#define setbit(s, i) (s|=(1LL<<(i)))
#define bit(s, i) (((s)>>(i))&1LL)
#define mask(i) ((1LL<<(i)))
#define builtin_popcount __builtin_popcountll
using ll=long long;
using ld=long double;
template <typename T> inline void read(T &x){
char c;
bool nega=0;
while((!isdigit(c=getchar()))&&(c!='-'));
if(c=='-'){
nega=1;
c=getchar();
}
x=c-48;
while(isdigit(c=getchar())) x=x*10+c-48;
if(nega) x=-x;
}
template <typename T> inline void writep(T x){
if(x>9) writep(x/10);
putchar(x%10+48);
}
template <typename T> inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
writep(x);
}
template <typename T> inline void writeln(T x){
write(x);
putchar('\n');
}
#define taskname "C"
int n, k;
string s;
string t;
int main(){
#ifdef Uiharu
if(fopen(taskname".in", "r"))
freopen(taskname".in", "r", stdin);
#endif // Uiharu
cin>>n>>k>>s;
for(char c: s){
int best, sign;
if((c-'a')>('z'-c)){
best=c-'a';
sign=-1;
}
else{
sign=1;
best='z'-c;
}
best=min(best, k);
t+=char(c+best*sign);
k-=best;
}
if(k) t="-1";
cout<<t;
}
E. Zbazi in Zeydabad
思路
如果暴力的话, 会超时;
考虑用树状数组优化。
因为是平面,所以用二维树状数组。
首先, 我们先预处理一个数组b, b[i][j][0]表示(i,j)这个点最远能向右延展到的长度;
b[i][j][1]表示这个点最远能向右上延展到的长度。
这样的话, 我们从上到下, 从左到右枚举每个点,那么统计的就是以当前这个点作为Z字形左下角的那个点, 能够形成的合法子矩阵数量。
树状数组查询(i, j)表示从第i行到第1行中z的数量。
那么Z字形最下面那条边的长度为b[i][j][0], 中间斜边长度为b[i][j][1]。所以, 其实说的不对。应该是两个方向所能延伸的最大的连续z的长度。
那么, 两者长度的最小值就是所能形成的最大的z。
但还有比他还小的z, 一共有query(i, j) - query(长度最小值)个;
但有可能Z字形上面那条边中没有z字符导致不合法。
所以我们每遍历到一个点, 把他相应最长长度向下的行数-1, 保证每次都是合法的, 最后可以直接算
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read(){
ll a=0,b=getchar(),c=1;
while(!isdigit(b))c=b=='-'?-1:1,b=getchar();
while(isdigit(b))a=a*10+b-'0',b=getchar();
return a*c;
}
const int N=3008;
struct node{
int x,y;
}t;
vector<node> d[N];
int n,m,a[N][N],b[N][N][2],c[N][N];
char s[N];
void add(int x,int y,int k){
while(x<N)c[x][y]+=k,x+=x&(-x);
}
int sum(int x,int y){
int res=0;
while(x>0)res+=c[x][y],x-=x&(-x);
return res;
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++)
a[i][j]=s[j]=='z';
}
for(int i=1;i<=n;i++)
for(int j=m;j>0;j--)
if(a[i][j])b[i][j][0]=b[i][j+1][0]+1,b[i][j][1]=b[i-1][j+1][1]+1;
ll ans=0;
for(int i=1;i<=n;i++){
for(int j=m;j>0;j--)
if(a[i][j]){
add(i,j,1),t.x=i,t.y=j;
if(i+b[i][j][0]-1<N)d[i+b[i][j][0]-1].push_back(t);
ans+=sum(i,j)-sum(i-min(b[i][j][0],b[i][j][1]),j);
}
for(int j=0;j<d[i].size();j++)
add(d[i][j].x,d[i][j].y,-1);
}
printf("%lld",ans);
return 0;
}