CF 628

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值