zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 86 (Rated for Div. 2)

    A. Road To Zero

    题意:给两个数x,y,你可以花费a的代价使得其中一个数+-1,也可以花费b的代价使得两个数都+-1,问最少需要多少代价使得两个数都变成0。

    思路:如果xy异号或者其中一个为0,那么一定不会使用b操作,此时只使用a操作。如果xy同号,可以先用b操作使得二者其中一个为0,再使用a操作使得二者都为0,而如果2次a操作的代价比1次b操作的代价还要低,那么就不会用b操作,也等价于只用a操作。所以有两种情况,直接用a操作,先用b操作把xy中绝对值较小的那一个变为0再用a操作。

     1 #include<bits/stdc++.h>
     2 #define LL long long
     3 #define dl double
     4 void rd(int &x){
     5  x=0;int f=1;char ch=getchar();
     6  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     7  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
     8 }
     9 void lrd(LL &x){
    10  x=0;int f=1;char ch=getchar();
    11  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    12  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
    13 }
    14 const int INF=1e9;
    15 const LL LINF=1e18;
    16 using namespace std;
    17 int T;
    18 int x,y,a,b;
    19 int main(){
    20 // freopen("in.txt","r",stdin);
    21  rd(T);
    22  while(T--){
    23   rd(x);rd(y);rd(a);rd(b);
    24   LL ans1=1ll*(abs(x)+abs(y))*a,ans2=1ll*abs(x)*b+1ll*abs(y-x)*a,ans3=1ll*abs(y)*b+1ll*abs(x-y)*a;
    25   printf("%lld
    ",min(ans1,min(ans2,ans3)));
    26  }
    27  return 0;
    28 }
    29 /**/
    View Code

    B. Binary Period

    题意:给一个长t(1e4)的01串,往中间插入若干个0或者1,使得最终长度<=2t且周期最小。一个字符串周期为k(>0的整数)则需要使得所有i满足f[i+k]=f[i]。输出最终的字符串。

    思路:放在b的位置肯定是特殊情况的构造题。容易发现,如果字符串全是0或者全是1,那么直接输出其本身即可,k取到1。而其他情况一定不是1,但是可以构造一个k取到2的情况。即长度为2t的0101交替出现的字符串,也用到了这个很常用的思路"每个长度为k的字符串对应原字符串一个字符,构造n个相同的串首尾相接"。

     1 #include<bits/stdc++.h>
     2 #define LL long long
     3 #define dl double
     4 void rd(int &x){
     5  x=0;int f=1;char ch=getchar();
     6  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     7  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
     8 }
     9 void lrd(LL &x){
    10  x=0;int f=1;char ch=getchar();
    11  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    12  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
    13 }
    14 const int INF=1e9;
    15 const LL LINF=1e18;
    16 const int N=105;
    17 using namespace std;
    18 int T;
    19 char t[N];
    20 void check(char *s){
    21  int n=strlen(s);
    22  for(int i=0;i<n-1;i++)
    23   if(s[i] != s[i+1]){
    24    for(int j=0;j<n;j++)putchar('0'),putchar('1');
    25    puts("");return ;
    26   }
    27  printf("%s
    ",t);return ;
    28 }
    29 int main(){
    30 // freopen("in.txt","r",stdin);
    31  rd(T);
    32  while(T--){
    33   scanf("%s",t);check(t);
    34  }
    35  return 0;
    36 }
    37 /**/
    View Code

     C. Yet Another Counting Problem

    题意:T(100)组数据,给出a,b(200),q(500)次询问,每次询问l到r(1~1e18)之间满足x%a%b != x%b%a的x的数目。

    思路:可以想到用前缀和的思想,问题转换为求1~l中满足题意的x。可以发现如果x与x+ab的情况完全相同,只需要看1~ab之间的数是否满足即可。对每组数据预处理出1~ab的情况即可。

     1 #include<bits/stdc++.h>
     2 #define LL long long
     3 #define dl double
     4 void rd(int &x){
     5  x=0;int f=1;char ch=getchar();
     6  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     7  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
     8 }
     9 void lrd(LL &x){
    10  x=0;int f=1;char ch=getchar();
    11  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    12  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
    13 }
    14 const int INF=1e9;
    15 const LL LINF=1e18;
    16 using namespace std;
    17 int T;
    18 int a,b,q;
    19 int s[205*205];
    20 LL get_ans(LL x){return (x/(a*b))*s[a*b] + s[x%(a*b)];}
    21 int main(){
    22 // freopen("in.txt","r",stdin);
    23  rd(T);
    24  while(T--){
    25   rd(a);rd(b);rd(q);s[0]=0;
    26   for(int i=1;i<=a*b;i++){
    27    s[i]=s[i-1];
    28    if(i%a%b != i%b%a)s[i]++;
    29   }
    30   for(int i=1;i<=q;i++){
    31    LL l,r;lrd(l);lrd(r);
    32    if(a == b)printf("0 ");
    33    else printf("%lld ",get_ans(r)-get_ans(l-1));
    34   }
    35   puts("");
    36  }
    37  return 0;
    38 }
    39 /**/
    View Code

    D. Multiple Testcases

    题意:n(2e5)个不超过k(2e5)的正整数,划分为最少的组数,使得每组中大于等于i的元素不超过ci个。输出分组方案。

    思路:我和答案的思路仍然不同,答案很优秀。

     答案:设si表示初始数字中大于等于i的数字个数,那么si/ci上取整的最大值就是答案。如果组数取得小于这个值,那么在处理si/ci上取整最大时对应的ci时将无法分配。而这个值本身又一定可以符合题意。就类似于抽屉原理的方法分配即可。

    我的思路:上限是n组,下限是1组,组少时能装下组多时便同样可以装下。于是进行二分。取定组数后判断时可以以抽屉原理类似的方式分配答案即可。(我在考场上用了毫无意义的堆,莫名增加了一个log的复杂度)。

     1 #include<bits/stdc++.h>
     2 #define LL long long
     3 #define dl double
     4 void rd(int &x){
     5  x=0;int f=1;char ch=getchar();
     6  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     7  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
     8 }
     9 void lrd(LL &x){
    10  x=0;int f=1;char ch=getchar();
    11  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    12  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
    13 }
    14 const int INF=1e9;
    15 const LL LINF=1e18;
    16 const int N=2e5+10;
    17 using namespace std;
    18 int n,k,m[N],c[N];
    19 struct ghb{
    20  int id,val;
    21  bool operator < (const ghb &o)const{
    22   return val < o.val;
    23  }
    24 };
    25 priority_queue<ghb>S;
    26 int bel[N];
    27 bool check(int x){
    28  while(!S.empty())S.pop();
    29  for(int i=1;i<=x;i++)S.push((ghb){i,0});
    30  for(int i=n,j=k;i>=1;i--){
    31   while(j > m[i])j--;
    32   ghb u=S.top();S.pop();
    33   if(u.val + c[j] <= 0)return 0;
    34   S.push((ghb){u.id,u.val-1});
    35   bel[i]=u.id;
    36  }
    37  return 1;
    38 }
    39 vector<int>P[N];
    40 int main(){
    41 // freopen("in.txt","r",stdin);
    42  rd(n);rd(k);
    43  for(int i=1;i<=n;i++)rd(m[i]);sort(m+1,m+n+1);
    44  for(int i=1;i<=k;i++)rd(c[i]);
    45  int l=1,r=n;
    46  while(l != r){
    47   int mid=l+r>>1;
    48   if(check(mid))r=mid;
    49   else l=mid+1;
    50  }
    51  check(l);
    52  printf("%d
    ",l);
    53  for(int i=1;i<=n;i++)P[bel[i]].push_back(m[i]);
    54  for(int i=1;i<=l;i++){
    55   printf("%d ",P[i].size());
    56   for(int j=0;j<P[i].size();j++)
    57    printf("%d ",P[i][j]);
    58   puts("");
    59  }
    60  return 0;
    61 }
    62 /**/
    View Code

    E. Placing Rooks

    题意:将n(2e5)个车放在n*n的棋盘上使得每个格子都可以被车攻击到,同时有k对车可以互相攻击。车就是象棋中的车。求方案数对998244353取模后的答案。

    思路:最终的答案一定满足"每行都有一个车"或者"每列都有一个车"。如果不是的话必然会出现行和列的交点无法被攻击到。最终答案就是"每行都有车"+“每列都有车”-“每行每列都有车”。而"每行每列都有车"的方案数在k=0时为n!,k!=0时为0。特判k=0的情况,我们便可以只研究"每行都有车",最终*2即可。我们发现如果一列有x个车,那么会有x-1对相互攻击的车。可以发现最多有n-1对相互攻击的车。所以当k>=n时方案数为0。当x列有车时,容易发现相互攻击的车的对数为n-x。于是仅当有n-k列有车时,相互攻击的车的对数为k。我们只关心多少列有车,车怎样摆放都合法。可以转换为组合数的基本问题。每一行的车视为一个小球,小球之间不同,需要放到n-k个互不相同的篮子中,方案数可以用第二类斯特林数来求得。随后我会整理一下基本的组合数问题解决方法。

     1 #include<bits/stdc++.h>
     2 #define LL long long
     3 #define dl double
     4 void rd(int &x){
     5  x=0;int f=1;char ch=getchar();
     6  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     7  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
     8 }
     9 void lrd(LL &x){
    10  x=0;int f=1;char ch=getchar();
    11  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    12  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
    13 }
    14 const int INF=1e9;
    15 const LL LINF=1e18;
    16 const int N=2e5+10;
    17 const int mod=998244353;
    18 using namespace std;
    19 int n;
    20 LL k;
    21 int fac[N],inv[N];
    22 int fst(int x,int y){
    23  int ans=1;
    24  while(y){
    25   if(y & 1)ans=1ll*ans*x%mod;
    26   x=1ll*x*x%mod;y>>=1;
    27  }
    28  return ans;
    29 }
    30 int C(int x,int y){
    31  return 1ll*fac[x]*inv[y]%mod*inv[x-y]%mod;
    32 }
    33 int main(){
    34 // freopen("in.txt","r",stdin);
    35  rd(n);lrd(k);
    36  fac[0]=1;for(int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mod;
    37  inv[n]=fst(fac[n],mod-2);for(int i=n-1;i>=0;i--)inv[i]=1ll*(i+1)*inv[i+1]%mod;
    38  if(k == 0)printf("%d
    ",fac[n]);
    39  else if(k >= n)printf("0
    ");
    40  else {
    41   int u=n-k;
    42   int ans=0;
    43   for(int i=0;i<=u;i++){
    44    int tmp=1ll*C(u,i)*fst(u-i,n)%mod;
    45    if(i&1)ans=(ans-tmp+mod)%mod;
    46    else ans=(ans+tmp)%mod;
    47   }
    48   printf("%d
    ",1ll*ans*2%mod*C(n,u)%mod);
    49  }
    50  return 0;
    51 }
    52 /**/
    View Code
  • 相关阅读:
    hnust Snowman
    hnust 可口可乐大促销
    hnust 聚宝盆
    hnust 搬书
    hnust 神奇的序列
    hnust 懒人多动脑
    hnust CZJ-Superman
    集合Set--BST实现
    快速排序
    位运算符
  • 原文地址:https://www.cnblogs.com/hyghb/p/12875892.html
Copyright © 2011-2022 走看看