(codeforces round#784)部分题(E~H)

G. Fall Down

#include<iostream>
#include<cstring>
using namespace std;
const int N = 55;
char g[N][N];

int n,m;
void fall(int line)//对每一列进行操作
{
    int pre = -1;//记录上一个'o'的位置
    for(int i = 0;i <= n;i++)
    {
        int cnt = 0;//记录'*'的个数
        if(g[i][line] == 'o')//遇到'o'
        {
            for(int k = i-1;k > pre;k--)//从后往前遍历到上一个'o' 记录'*'的个数
                if(g[k][line] == '*') cnt++;

            for(int x = i-1;x > pre;x--)//将'*'叠到'o'的上面
                if(cnt > 0) g[x][line] = '*',cnt--;
                else  g[x][line] = '.';//剩下填'.'
        
            pre = i;
        }
    }
}
int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n >> m;
        for(int i = 0;i < n;i++) cin >> g[i];
        for(int i = 0;i < m;i++) g[n][i] = 'o';//将第n行全部置成'o'这样就不用考虑边界问题

        for(int i = 0;i < m;i++)  fall(i);//对于每一列fall一遍
        for(int i = 0;i < n;i++)
        {
            for(int j = 0;j < m;j++)
            {
                cout << g[i][j];
            }
            cout << endl;
        }
    }
    return 0;
}

F. Eating Candies

#include<iostream>
#include<cstring>
using namespace std;

const int N = 200010;
int a[N];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(a,0,sizeof a);//记得每次初始化一下列表
        int n;
        scanf("%d",&n);//数据范围比较大建议使用scanf读入
        for(int i = 0;i < n;i ++) scanf("%d",&a[i]);

        int cnt = 0;//俩个人吃的糖的总数
        int maxv = 0;//记录最大的吃糖数
        int l = 0, r = n-1;//从左右开始模拟
         
        int suml = 0,sumr = 0;
        while(l <= r)
        {
                                         //一定要带上等号 不然进入不了下一个while
            while(l <= r && suml <= sumr)//当糖还没吃完 并且suml <= sumr 那么继续吃
            {                            //第一次的时候 suml = sumr = 0可以进入循环
                suml += a[l++];
                cnt  ++;
                if(suml == sumr) //相等的时候 记录一下吃糖最大值
                {
                    maxv = cnt;
                }
            }
            while(l <= r && sumr <= suml)//同理
            {
                sumr += a[r--];
                cnt ++;
                if(suml == sumr) 
                {
                    maxv = cnt;
                }
            }
        }
        printf("%d\n",maxv);
    }
    return 0;
}

E. 2-Letter Strings

思路:例子jf,jf,jk,jk,jk

1.先统计俩个位置字母出现位置 第一个位置的 j 出现 5次 第二个位置 f 出现2次 k 出现3次

2.先不管重复的部分(假设没有重复)在第一个位置是j 有5 个 从5个里面选2个 利用我们提前打好的表 res += f[5] 依次类推 初步得到res = 14

3.处理相同的部分 我们事先将重复的字母对 存到map当中

比如这里的jf,jf重复俩次 那么res-=f[2] * 2(因为j重复2次 f重复3次);6

jkjkjk 那么res-=f[3] *2; 得到res = 14 - 2 - 6 = 6

具体看代码

#include<iostream>
#include<algorithm>
#include<cstring>
//一般使用pair 先把first second定义成比较短的 减少代码长度
#define x first//使用x 代替first
#define y second//使用y 代替second
using namespace std;
const int N = 100010;
typedef long long LL;//减少代码量
typedef pair<int,int> PII;

int a[13];//用来存每个第一个字母出现的次数
int b[13];//用来存每个第二个字母出现的次数
map<PII,int> st;//判重
int f[N];//f[i] 表示从i个里面选2个的方案
void init()
{
    for(int i = 2;i < N;i++)
    {
        f[i] = i * (i-1)/2;//简单的组合数
    }
}

void reset()
{
    memset(a,0,sizeof a);
    memset(b,0,sizeof b);
    st.clear();
}

int main()
{
    init();
    int T;
    cin >> T;
    while(T--)
    {
        reset();//每次循环 重置一遍a,b,st;
        int n;
        cin >> n;
        for(int i = 1;i <= n;i++)
        {
            char ch[3];
            scanf("%s",ch);

            int ch1 = ch[0] - 'a';
            int ch2 = ch[1] - 'a';
            a[ch1] ++;
            b[ch2] ++;
            if(st.count({ch1,ch2})) //如果该字母对出现过 那么记录下来
            {
                st[{ch1,ch2}] ++;
            }
            else 
            {
                st[{ch1,ch2}] = 1;
            }
        }
        LL res = 0;//依次遍历第一个位置和第二个位置的字母 出现的个数 
        for(int i = 0;i < 13;i++) res += (LL)f[a[i]],res += (LL)f[b[i]];
        //再减去 重复的部分
        for(auto it : st)
        {
            int a = it.x.x, b = it.x.y,cnt = it.y;
            res = res- (LL)f[cnt]*2;//第一个位置跟第二个位置 总共要减去2倍
        }

        cout << res << endl;


    }
}

H. Maximal AND

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 32;

int cnt[N];//记录每一位一的个数

int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        memset(cnt,0,sizeof cnt);//多组测试数据记得重置一下cnt数组
        int n,k;
        cin >> n >> k;
        for(int i = 0;i < n;i++)
        {
            int x;
            cin >> x;
            for(int j = 30;j>=0;j--)//对于每一个读进来的x 枚举他的30位(0 <= j <= 30)
            {
                if(x >> j & 1) cnt[j]++;//判断i的第j位是不是1
            }
        }
        int ans = 0;
        for(int i = 30;i >=0;i--)//因为只有k次操作 越大越好所以从最高位开始枚举
        {
            int p = n - cnt[i];//第i位不是1的个数
            if(p <= k)//如果个数小于k 说明k可以将该位全部变成1 那么在进行&运算时 该位就为1了
            {
                k-=p;//次数减去
                ans += 1<<i;//累加答案
            }
        }

        cout << ans << endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值