acwing转战CSDN,发现CSDN写题解更方便
比赛链接
A-小红小紫投硬币(数学推导)
题意
A和B投硬币,有正反两面的结果,概率为0.5,A投了n个硬币,B投了n+1个硬币,求B投的正面次数比A的多的概率
思路
可以证明,无论n等于多少,概率都是0.5,输出即可
代码
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long
const LL N=1e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了
void solve()
{
double n;
cin>>n;
cout<<"0.5"<<endl;
}
int main()
{
int t=1;
//cin>>t;
while(t--)
{
solve();
}
return 0;
}
B-小红的字符串(字符串)
题意
给定一个由小写字母组成的字符串s,可以进行一种操作:对字符串中一个字符进行右移操作,’z‘右移变为’a‘,求把s变为回文串的最小操作数。
思路
注意看题,只能右移,不能左移(我没看仔细,引以为戒),求出对称的两个字符串变成相同字符串所需要的次数,有两种情况:可以是左边字符右移,可以是右边字符右移,取最小累加即可。
代码
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long
const LL N=1e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了
int work(char a,char b)
{
if(a>b)swap(a,b);
int s=abs(a-b);
int ss=(a-'a'+'z'-b)+1;
return min(s,ss);
}
void solve()
{
string s;
cin>>s;
int n=s.size();
int ans=0;
for(int i=0;i<n/2;i++)
{
if(i>=n/2)continue;
int tmp=work(s[i],s[n-1-i]);
ans+=tmp;
}
cout<<ans<<endl;
}
int main()
{
int t=1;
//cin>>t;
while(t--)
{
solve();
}
return 0;
}
C-小红的 01 消除(贪心 字符串)
题意
给定一个由0和1组成的字符串,可以进行3种操作:
1.删除11子串
2.删除01子串
3.删除00子串
操作分别有x,y,z的次数限制
求进行操作2的最多次数
思路
x和z没啥用,只需要检测01的个数,遍历整个字符串,有两种读取模式,第一步先读连续的0,再读后面连续的1,两个个数取最小就是01的个数,重复两种模式,直到字符串结束,然后再和y取小值就行。
代码
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long
const LL N=1e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了
void solve()
{
int n;
string s;
cin>>n>>s;
int x,y,z;
cin>>x>>y>>z;
int wait=0;
int idx=0;
int res=0;
int last0=0,last1=0;
while(idx<n)
{
if(wait==0)
{
if(idx<n&&s[idx]=='0')
{
while(idx<n&&s[idx]=='0')idx++,last0++;
wait=1;
}
else if(idx<n&&s[idx]=='1')
{
idx++;
}
}
else
{
if(idx<n&&s[idx]=='1')
{
while(idx<n&&s[idx]=='1')idx++,last1++;
//cout<<last0<<" "<<last1<<endl;
res+=min(last1,last0);
last1=0;
last0=0;
wait=0;
}
else if(idx<n&&s[idx]=='0')
{
idx++;
}
}
}
cout<<min(res,y)<<endl;
}
int main()
{
int t=1;
//cin>>t;
while(t--)
{
solve();
}
return 0;
}
D-小红组比赛(分组DP)
题意
一共有n场比赛,每场比赛有m道题,现在从这些比赛中抽n道题(每场比赛必须抽一道),组成一场比赛,有一个目标难度,求比赛难度(题目难度相加)与目标难度的最小绝对值。
思路
分组dp是看大佬的讲解学会的:背包问题----分组背包(超详细讲解)-CSDN博客
分组dp的板子题,赛时写了一个dfsTLE了;
和01背包类似,但是分组背包把物品分为n个组,每个组最多只能选一个,然后求最大,这道题求的是最小绝对值,所以可以存储在范围中的每个数是否出现过,可以发现,到第n层的出现数字可以由第n-1层的出现数字推出,最后在第n层出现的数字中取最小绝对值就好了。
代码
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long
const LL N=1e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了
LL num[110][30];
LL ans[N];
void solve()
{
LL n,m;
cin>>n>>m;
LL maxx=0;
for(int i=1;i<=n;i++)
{
LL tmp=0;
for(int j=1;j<=m;j++)cin>>num[i][j],tmp=max(tmp,num[i][j]);
ans[i]=tmp;
maxx+=tmp;
}
vector<bool> dp(maxx+1,false);
LL k;
cin>>k;
dp[0]=true;
for(int i=1;i<=n;i++)
{
vector<bool> dp2(maxx+1,false);
for(int j=1;j<=m;j++)
{
for(int k=maxx-num[i][j];k>=0;k--)
{
if(dp[k])
{
dp2[k+num[i][j]]=true;
}
}
}
dp=dp2;
}
LL ans=INF;
for(int i=maxx;i>=0;i--)
{
if(dp[i])ans=min(ans,abs(i-k));
}
cout<<ans<<endl;
}
int main()
{
int t=1;
//cin>>t;
while(t--)
{
solve();
}
return 0;
}
E-折半丢弃(二分 MEX)
题意
给定一个由n个整数构成的数组a,可以对数组进行一种操作,取一个数,进行折半下取整,然后求若干操作后能够取得的最大MEX值(数组中没有出现的最小整数)
思路
我们可以对MEX值进行二分,具有二分的性质,因为当数组可以使得MEX值为a时,也可以使得MEX值为(b<a),所以,我们先对MEX-1进行二分,找到满足条件的最大MEX(右端点),check函数写法:先把所有的大于mid的数折半为小于或等于mid的数,然后再从大到小进行枚举,出现次数大于1的大数可以折半为小数,然后通过贪心构造后判断是否能够实现从0-mid的数字全部出现过。
代码
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long
const LL N=1e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了
LL a[N];
LL b[N];
LL n;
bool check(LL mid)
{
map<LL,LL> has;
for(int i=1;i<=n;i++)
{
b[i]=a[i];
while(b[i]>mid)
{
b[i]/=2;
}
has[b[i]]++;
}
LL idx=mid;//从大到小进行构造
while(idx>=0&&has[idx])
{
has[idx/2]+=has[idx]-1;//大的留一个,其他全化为小的
idx--;
if(idx<=-1)break;
}
return idx==-1;//枚举是否能够使得MEX=mid+1(是否存在0-mid)
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
LL l=0,r=1e9+10;
while(l<r)
{
LL mid=(l+r+1)/2;
if(check(mid))l=mid;//求右端点,向左延伸,封左
else r=mid-1;
}
cout<<l+1<<endl;
}
int main()
{
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
小小菜鸡水平不足,剩下两道题看不懂了,先溜了