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;
}
}