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\n",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\n",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\n",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\n",fac[n]);
39  else if(k >= n)printf("0\n");
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\n",1ll*ans*2%mod*C(n,u)%mod);
49  }
50  return 0;
51 }
52 /**/
View Code

 

posted @ 2020-05-13 17:01  hyghb  阅读(221)  评论(0编辑  收藏  举报