Educational Codeforces Round 96 Rated for Div. 2 Oct/11/2020 17:05UTC+8
比赛链接:https://codeforces.com/contest/1430
比赛记录:https://blog.csdn.net/cheng__yu_/article/details/105395197
A. Number of Apartments
题意: 给定一个 n 问能否由 3 、5 、7 这些数字组成。 ( 1 ≤ n ≤ 1000 ) (1\le n \le 1000) (1≤n≤1000)
思路:
- 数据范围很小,直接暴力就可以了
- 也可以 dp 转移一下
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5;
int t,n;
bool ok;
void solve()
{
for(int i=0;; ++i)
{
if(3*i>n) break;
for(int j=0;; ++j)
{
if(3*i+5*j>n) break;
for(int k=0;; k++)
{
if(3*i+5*j+7*k>n) break;
if(3*i+5*j+7*k==n)
{
printf("%d %d %d\n",i,j,k);
ok=1;
return;
}
}
}
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
ok=0;
solve();
if(!ok) puts("-1");
}
return 0;
}
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1000+5;
int t,n;
int a[maxn],b[maxn],c[maxn];
void init()
{
memset(a,-1,sizeof(a));
memset(b,-1,sizeof(b));
memset(c,-1,sizeof(c));
a[0]=0,b[0]=0,c[0]=0;
for(int i=1; i<=1000; ++i)
{
if(i>=3&&a[i-3]!=-1)
{
a[i]=a[i-3]+1;
b[i]=b[i-3];
c[i]=c[i-3];
}
else if(i>=5&&b[i-5]!=-1)
{
a[i]=a[i-5];
b[i]=b[i-5]+1;
c[i]=c[i-5];
}
else if(i>=7&&c[i-7]!=-1)
{
a[i]=a[i-7];
b[i]=b[i-7];
c[i]=c[i-7]+1;
}
}
}
int main()
{
init();
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
if(a[n]==-1) puts("-1");
else printf("%d %d %d\n",a[n],b[n],c[n]);
}
return 0;
}
D. String Deletion (模拟)
题意:给定一个字符串,轮流执行两个操作:
- 选择任意一个位置删除
- 将相同字符的前缀删除
问最多可以执行几轮。
思路:
- 将所有相同字符缩成一段
- 如果第一段的长度大于 1 ,那么直接删除第一段即可
- 如果第一段的长度等于 1 ,那么判断后面是否有长度大于 1 的段,如果存在则删除长度大于 1 的段中一个字符,再删除第一段。否则,直接删头删尾都行。(此时所有段长度为 1 ,删中间会重新出现大于 1 的段,不可取)
#include <bits/stdc++.h>
#define se second
#define ll long long
using namespace std;
const int maxn=2e5+5;
int t,n;
char s[maxn];
pair<int,int> p[maxn];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%s",&n,s+1);
s[0]='2';
int k=0;
for(int i=1; i<=n; ++i)
if(s[i]==s[i-1]) p[k].se++;
else p[++k]= {s[i]-'0',1};
set<int> s;
for(int i=1; i<=k; ++i)
if(p[i].se>=2) s.insert(i);
int ans=0;
for(int i=1; i<=k; ++i)
{
ans++;
if(p[i].se==1)
{
auto it=s.lower_bound(i);
if(it==s.end()) i++;
else
{
int pos=*it;
p[pos].se--;
if(p[pos].se==1) s.erase(it);
}
}
}
printf("%d\n",ans);
}
return 0;
}
E. String Reversal (贪心)
题意: 给定一个字符串,问最少需要对相邻元素交换多少次才能实现翻转操作
思路:
- 对于翻转后的每一个字符,都是从原字符串中的最靠左边的字符交换过来的。记录一下,当前字符左边有多少个空位,减去这些空位就是需要交换的次数
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+5;
int n;
string s;
deque<int> vec[maxn];
int C[maxn];
int lowbit(int x)
{
return x&-x;
}
void add(int x,int val)
{
for(int i=x; i<=n; i+=lowbit(i))
C[i]+=val;
}
int getsum(int x)
{
int res=0;
for(int i=x; i>0; i-=lowbit(i))
res+=C[i];
return res;
}
int main()
{
scanf("%d",&n);
cin>>s;
string t=s;
s="0"+s;
for(int i=1; i<=n; ++i)
{
int x=s[i]-'a'+1;
vec[x].push_back(i);
}
reverse(t.begin(),t.end());
ll ans=0;
for(int i=0; i<n; ++i)
{
int x=t[i]-'a'+1;
int pos=vec[x].front();
vec[x].pop_front();
ans+=i+getsum(pos);
add(pos,-1);
}
printf("%lld\n",ans);
return 0;
}