Codeforces Round #471 div.2 ABC题解

  • 其实我是震惊的
    • A
    • B
    • C

其实我是震惊的

我被A题卡住了,21分钟才过.B题倒是挺快,29分钟.然后我一直想C和D.
C是个数论题我觉得还能做,D我不会.

但是我发现1个多小时过去了C题做出的人数都没有超过100,这令我非常惊讶.
这时我点到Friends Standing,发现某巨佬B题被hack了.
我去注意B题的题意,发现题目中说必须要把字符串分成两个子串使它们都可爱.
我稍微考虑了一下,把B题锁掉了.然后跑到room里面准备hack别人.
结果还真给我用abcdef这个数据成功了一次.
更重要的是,我只做出2题居然能排名190,加了92rating.
具体见下面题解吧.

A

这题有两个需要计算的地方:
第一个:求现在的时间离20点还有多久.
第二个:取整.向上取整可以用ceil(a,b)=(a+b-1)/b.
当然我这里用的是a%b==0?a/b:a/b+1,因为这样比较直接.

#include
namespace chtholly{
#define re0 register int
#define rec register char
#define p32 putchar(' ')
#define pl puts("")
int read(){
  re0 x=0,f=1;rec c=getchar();
  for (;!isdigit(c);c=getchar()) f^=c=='-';
  for (;isdigit(c);c=getchar()) x=x*10+c-'0';
  return x*(f?1:-1);
  }
int write(int x){
  if (!x) return putchar(48);
  if (x<0) x=-x,putchar('-');
  re0 bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) putchar(bit[i]+48);
  }
}
using namespace chtholly;
#define chu(a,b) ((a)%(b)==0?(a)/(b):(a)/(b)+1)//向上取整
using namespace std;
int hh,mm,h,d,c,n;

int suan(int hour,int minute)//算现在离20点还有多久,(20-hh)*60-mm
{
return (20-hour)*60-minute;
}

int main()
{
cin>>hh>>mm>>h>>d>>c>>n;
double ans=0;
if (hh<20)//现在没有到20点.
  {
  double tmp1=chu(h,n)*c*1.0;//不等到20点直接买包子.
  double tmp2=chu(h+suan(hh,mm)*d,n)*c*0.8;//把饥饿度加上d*到20点的分钟数.
  printf("%.4lf",min(tmp1,tmp2));//取较小值
  }
else 
  {
  printf("%.4lf",chu(h,n)*c*0.8);//超过20点没有选择,肯定打8折.
  }
}

B

题目大意:给一个字符串,问它能否被分成两个子序列使得这两个子序列均恰好含有2种不同的字母.

/*
看到会发现这题坑点非常多,注意每一个细节.
首先这个字符串不能含有4种以上的字母,否则你懂的.
同理它的长度也不能小于4.(一个序列要想有两种字符它至少得有两个字符.)
剩下的情况考虑字母的种数为2,3,4.
如果字母种数为2,不能有一种的个数是1,否则另一个串里会只剩一种字符,游戏就结束了.
字母种数为3,只要有一种个数超过1就可以了.由于刚才已经判过长度不小于4,因此可以直接输出"Yes".
种数为4,没有反例,直接"Yes".
*/
#include
namespace chtholly{
#define re0 register int
#define rec register char
#define p32 putchar(' ')
#define pl puts("")
int read(){
  re0 x=0,f=1;rec c=getchar();
  for (;!isdigit(c);c=getchar()) f^=c=='-';
  for (;isdigit(c);c=getchar()) x=x*10+c-'0';
  return x*(f?1:-1);
  }
int write(int x){
  if (!x) return putchar(48);
  if (x<0) x=-x,putchar('-');
  re0 bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) putchar(bit[i]+48);
  }
}
using namespace chtholly;
using namespace std;
string s;int cnt[27];
int main()
{
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
cin>>s;
for (char c:s) cnt[c-97]++;
int ans=0;
for (int i=0;i<26;++i)
  {
  if (cnt[i]) ans++;
  if (ans>4) return puts("No"),0; 
  }
if (ans<2||s.size()<4) return puts("No"),0;
if (ans==2)
  {
  for (int i=0;i<26;++i)
    if (cnt[i]==1) return puts("No"),0;  
  puts("Yes");
  }
else puts("Yes");
}

C

某巨佬用了一个容斥,写挂了先T再WA.
这题显然不能直接枚举.但我们可以得到一点思路.
如果直接枚举所有符合条件的数,你要枚举到1e9.
但是考虑一个问题:对于1e6-1e9之间的数a,能让a^p在1e18以内的p只有2.
那么我们用get(r)-get(l-1)差分求得答案.
对于n以内满足条件的数来说,我们把答案分成完全平方数和非完全平方数两种可能.
对于前面那种情况来说,可以O(1)用sqrt(n)求出.
后面那种我们进行预处理,把所有的数放到一个vector里,询问的时候直接二分不超过n的最大值.
这样只用枚举到1e6了.

#include
typedef long long ll;
namespace chtholly{
#define re0 register int
#define rec register char
#define p32 putchar(' ')
#define pl puts("")
ll read(){
  register ll x=0;re0 f=1;rec c=getchar();
  for (;!isdigit(c);c=getchar()) f^=c=='-';
  for (;isdigit(c);c=getchar()) x=x*10+c-'0';
  return x*(f?1:-1);
  }
int write(ll x){
  if (!x) return putchar(48);
  if (x<0) x=-x,putchar('-');
  re0 bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) putchar(bit[i]+48);
  }
}
using namespace chtholly;
using namespace std;
const ll mulu=1e18;
int q=read();
vector ans;

void pre()//预处理
{
ll i,j;
for (i=2;i*i*i<=mulu;++i)//枚举到1e6 
  {
  for (j=i*i;j<=mulu/i;)//注意循环终止条件.这里做得不好就爆long long了.
    {
    j*=i;//注意以上是从3次方开始枚举.
    ll t=sqrt(j);
    if (t*t!=j) ans.push_back(j);//判断sqr(sqrt(j))是不是j,如果是就表示它是完全平方数,我们就不用加它,询问的时候会求到的.
    }
  }
sort(ans.begin(),ans.end());
ans.erase(unique(ans.begin(),ans.end()),ans.end());//排序,去重.
}

ll get(ll n)
{
return !n?0:upper_bound(ans.begin(),ans.end(),n)-ans.begin()+1ll*sqrt(n);
//比n大的第一个数的位置减起始位置就是询问结果,再加个sqrt(n).
}

int main()
{
pre();
for (;q--;)
  {
  ll l=read(),r=read();
  write(get(r)-get(l-1)),pl;
  }
}

你可能感兴趣的:(codeforces)