CF每日一练(1.17)
A - Find Divisible
水题,直接输出 l 2*l 即可
B - Substring Removal
记录左边有l
个字母相同,右边有r
个字母相同,肯定会有 r+l+1种,然后如果有s[1] == s[n]
,那么还可以移除中间的子串,要再加上l*r
即可(因为题目保证有两个不同的字符)
#include <iostream>
#include <cstdio>
using namespace std;
const int mod = 998244353;
int n;
char s[200010];
int main()
{
scanf("%d %s",&n,s);
int l=1,r=1;
for(;s[l-1]==s[l];l++);
for(;s[n-r-1]==s[n-r];r++);
long long ans = l+r+1;
if(s[0] == s[n-1])
ans = (ans+1ll*l*r)%mod;
cout<<ans<<endl;
return 0;
}
C - Polygon for the Angle
题意:给一个角度ang(1<=ang<180)
然后输出如图所示规则的最小正n边形的边数
分析:abc三点构成一个三角形,而三角形内角的比例就对应于它们各自对应的那段边数比。如图,54度对应三份,剩下的分别对应五份和两份。
所以,对于任意一个角度ang
,先求出g=gcd(ang,180)
,即每一边可以对应多少度,然后 n=180/g
即为正n边形的边数,wait wait!是不是有点太快了,别忘了我们的前提条件,我们是用三角形内角比例等于对应边数比得到的结论,我们要让它满足能够组成三角形这一条件,所以发现当 ang/180==(n-1)/n
时(想一想为什么是这样),就无法组成三角形(因为只剩下一份了,不够与ang组成三角形),这个时候只需将 n乘以2即可。
#include <bits/stdc++.h>
using namespace std;
int T,ang,n;
int main()
{
cin>>T;
while(T--)
{
cin >> ang;
int n = 180/__gcd(ang,180);
if(ang * n / 180 == n-1){
n*=2;
}
cout << n << endl;
}
}
D - Easy Problem
题意:有一长度为n的字符串,每一字符都有一个权值,要求现在从中取出若干个字符,使得字符串中没有子串hard
,(这里的子串在原串中不需要连续)。求取出字符的最小权值和。
分析:dp,
- h的决策只能时消灭h
- a的决策是将前面的h消灭,或者是以最优策略消灭前面顺序符合的
ha
- 同理,r的策略是使用a的策略消灭ha,或者是以最优策略消灭
har
- d同理。
最后输出解决d的情况即可。因为d里面包含了前面所有的情况。
考虑到权值比较大,n为1e5,可能会爆int
#include <cstdio>
#include <iostream>
#include <string>
using namespace std;
const int inf = 0x3f3f3f3f;
string s;
long long n,x;
long long h,a,r,d;
int main()
{
cin>>n>>s;
for(int i=0;i<n;i++)
{
cin>>x;
if(s[i] == 'h')h+=x;
else if(s[i]=='a') a = min(h,a+x);
else if(s[i]=='r') r=min(a,r+x);
else if(s[i]=='d') d=min(r,d+x);
}
cout<<d<<endl;
return 0;
}