BestCoder Round #93 ABC

A:

题目大意:

将数组划分成最少的段,每段的数两两不同。

题解:直接用一个map记录一个数是否出现过,贪心的每次取最多个数就好。



B:

题目大意:

给出一个0-9组成的字符串,问能否删掉K个数字,使得最后形成的数没有前导零且能被3整除。

题解:

最后会留下N-K个数,枚举第一个数的位置,然后问题就可以转化为判断同余方程0*x+1*y+2*z = v (mod 3) 是否有解。   其中(x+y+z=K-1  && x<=a && y<=b && z<=c)

设:

x = i (mod 3)

y = j (mod 3)

z = k (mod 3)

在[0,2]范围里枚举i,j,k

然后可行的条件是:

1.    i<=a , j <=b , k <=c

2.    0*i+1*j+2*k = v (mod 3)

3.    i+j+k <= K-1

4.    3*( (a-i)/3+(b-j)/3+(c-k)/3 )+ i+ j + k >= K-1

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <map>
 8 using namespace std;
 9
10 #define X first
11 #define Y second
12 #define N 100010
13 #define M 500010
14
15 typedef long long ll;
16 const int INF=1ll<<30;
17
18 char s[N];
19 int dp[N][3],suf[N][3];
20
21 bool Check(int a,int b,int c,int r,int n)
22 {
23     for (int i=0;i<3 && i<=a;i++)
24     {
25         for (int j=0;j<3 && j<=b;j++)
26         {
27             for (int k=0;k<3 && k<=c;k++)
28             {
29                 if (i+j+k>n) continue;
30                 if ((j+k*2)%3!=r) continue;
31                 if ((n-i-j-k)%3) continue;
32                 int t=(a-i)/3+(b-j)/3+(c-k)/3;
33                 if (3*t>=n-i-j-k) return true;
34             }
35         }
36     }
37     return false;
38 }
39
40 int main()
41 {
42     //freopen("in.in","r",stdin);
43     //freopen("out.out","w",stdout);
44
45     int T,n,K; scanf("%d",&T);
46     while (T--)
47     {
48         scanf("%d%d",&n,&K);
49         scanf("%s",s+1);
50         K=n-K;
51         if (K==1)
52         {
53             bool flag=false;
54             for (int i=1;i<=n;i++) if ((s[i]-‘0‘)%3==0) flag=true;
55             puts(flag? "yes":"no");
56             continue;
57         }
58         suf[n+1][0]=suf[n+1][1]=suf[n+1][2]=0;
59         for (int i=n;i>=1;i--)
60         {
61             suf[i][0]=suf[i+1][0];
62             suf[i][1]=suf[i+1][1];
63             suf[i][2]=suf[i+1][2];
64             suf[i][(s[i]-‘0‘)%3]++;
65         }
66         bool flag=false;
67         for (int i=1;i<=n;i++)
68         {
69             if (s[i]==‘0‘) continue;
70             int a=suf[i+1][0],b=suf[i+1][1],c=suf[i+1][2];
71
72             int r=(s[i]-‘0‘)%3,need=r==0? 0:3-r;
73             if (Check(a,b,c,need,K-1)) flag=true;
74         }
75         puts(flag? "yes":"no");
76     }
77
78     return 0;
79 }



C:

由26个小写字母组成长度为n的字符串, 定义一次变化后 字母i会变成a[i], 问一个随机的字符串 变换成自身的期望次数。

题解:

首先求出置换环, 因为总共才26个字母,置换环不同的大小最多有6种(1+2+3+4+5+6<26  1+2+3+4+5+6+7>26)。

设字母i变换fi次变成自身,fi就是它所在置换环大小。

一个串变成自身所需的次数就是串内所有字母的fi的最小公倍数。

所以可以枚举串内有哪些fi, 最多$2^6$ 种情况。

对于当前枚举的特定的fi集合S, 可以用容斥原理来计算总的次数, 即枚举哪些fi没被用上,  用二项式定理容易证明 两次枚举的复杂度一共是$3^6$

具体实现看代码:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <vector>
  6 #include <cmath>
  7 #include <queue>
  8 using namespace std;
  9
 10 #define X first
 11 #define Y second
 12 #define N 100010
 13 #define M 11
 14
 15 typedef long long ll;
 16 const int Mod=1000000007;
 17 const int INF=1<<30;
 18
 19 char s[26];
 20 int cnt[27],a[10],b[10];
 21 int pw[27];
 22 bool vis[26];
 23
 24 int Lcm(int x,int y)
 25 {
 26     int lcm=x*y,tmp;
 27     while (y)
 28     {
 29         tmp=x%y;
 30         x=y,y=tmp;
 31     }
 32
 33     return lcm/x;
 34 }
 35
 36 int Power(int x,int P)
 37 {
 38     if (pw[x]) return pw[x];
 39     int res=1,xx=x;
 40     for (;P;P>>=1)
 41     {
 42         if (P&1) res=1ll*res*x%Mod;
 43         x=1ll*x*x%Mod;
 44     }
 45     return pw[xx]=res;
 46 }
 47
 48 int Solve(int len,int n)
 49 {
 50     //for (int i=0;i<n;i++) cout<<i<<" "<<a[i]<<" "<<b[i]<<endl;
 51     int lim=1<<n,val,cnt,m,t,res=0;
 52     for (int mask1=1;mask1<lim;mask1++)
 53     {
 54         val=1; t=0;
 55         for (int i=0;i<n;i++) if (mask1&(1<<i)) val=Lcm(val,a[i]),t+=b[i];
 56         cnt=Power(t,len);
 57         for (int mask2=(mask1-1)&mask1;mask2;mask2=(mask2-1)&mask1)
 58         {
 59             int op=1; m=t;
 60             for (int j=0;j<n;j++) if (mask2&(1<<j)) op=-op,m-=b[j];
 61             cnt+=op*Power(m,len); cnt%=Mod;
 62         }
 63
 64         res+=1ll*cnt*val%Mod; res%=Mod;
 65     }
 66     return res<0? res+Mod:res;
 67 }
 68
 69 int main()
 70 {
 71     //freopen("in.in","r",stdin);
 72     //freopen("out.out","w",stdout);
 73
 74     int T,len; scanf("%d",&T);
 75     while (T--)
 76     {
 77         scanf("%d%s",&len,s);
 78         memset(vis,0,sizeof(vis));
 79         memset(cnt,0,sizeof(cnt));
 80         memset(pw,0,sizeof(pw));
 81         for (int i=0;i<26;i++)
 82         {
 83             if (!vis[i])
 84             {
 85                 int c=0,x=i;
 86                 do
 87                 {
 88                     c++;
 89                     x=s[x]-‘a‘;
 90                     vis[x]=true;
 91                 }while (x!=i);
 92                 cnt[c]+=c;
 93             }
 94         }
 95         int n=0;
 96         for (int i=1;i<=26;i++) if (cnt[i]) a[n]=i,b[n++]=cnt[i];
 97         printf("%d\n",Solve(len,n));
 98     }
 99     return 0;
100 }

时间: 2025-01-02 03:23:33

BestCoder Round #93 ABC的相关文章

BestCoder Round #93

这么快两天就过去了啊--昨天是April Fool's Day,但绝对是我过的所有April Fool's Day里最没意思的一个-- 估计再不写就要忘了--还是写写吧= = 说好7:00到机房,然而我迟到了3min,等我进机房的时候别人都已经开始码T1了-- 总之T1就是个大水题= =每次尽可能往后取直到不能再取为止,配合奇技淫巧STL/pbds黑科技就随便水了-- 1 #include<cstdio> 2 #include<cstring> 3 #include<algo

BestCoder Round #11 (Div. 2) 前三题题解

题目链接: huangjing hdu5054 Alice and Bob 思路: 就是(x,y)在两个參考系中的表示演全然一样.那么仅仅可能在这个矩形的中点.. 题目: Alice and Bob Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 216    Accepted Submission(s): 166 Problem De

BestCoder Round #11 (Div. 2) 题解

HDOJ5054 Alice and Bob Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 302    Accepted Submission(s): 229 Problem Description Bob and Alice got separated in the Square, they agreed that if they

从lca到树链剖分 bestcoder round#45 1003

bestcoder round#45 1003 题,给定两个点,要我们求这两个点的树上路径所经过的点的权值是否出现过奇数次.如果是一般人,那么就是用lca求树上路径,然后判断是否出现过奇数次(用异或),高手就不这么做了,直接树链剖分.为什么不能用lca,因为如果有树退化成链,那么每次询问的复杂度是O(n), 那么q次询问的时间复杂度是O(qn) 什么是树链剖分呢? 就是把树的边分成轻链和重链 http://blogsina.com.cn/s/blog_6974c8b20100zc61.htmlh

hdu 5195 DZY Loves Topological Sorting BestCoder Round #35 1002 [ 拓扑排序 + 优先队列 || 线段树 ]

传送门 DZY Loves Topological Sorting Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 221    Accepted Submission(s): 52 Problem Description A topological sort or topological ordering of a directed

BestCoder Round #29 1003 (hdu 5172) GTY&#39;s gay friends [线段树 判不同 预处理 好题]

传送门 GTY's gay friends Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 264    Accepted Submission(s): 57 Problem Description GTY has n gay friends. To manage them conveniently, every morning he o

[BestCoder Round #3] hdu 4909 String (状压,计数)

String Problem Description You hava a non-empty string which consists of lowercase English letters and may contain at most one '?'. Let's choose non-empty substring G from S (it can be G = S). A substring of a string is a continuous subsequence of th

BestCoder Round #11 (Div. 2)题解集合

Alice and Bob Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 155    Accepted Submission(s): 110 Problem Description Bob and Alice got separated in the Square, they agreed that if they get sepa

BestCoder Round #1 1001 &amp;&amp; 1002 hdu 4857 4858

hdu 4857 逃生 第一题是拓扑排序,不是按照字典序最小输出,而是要使较小的数排在最前面..赛后弄了好久,才比较明白,我一直以为 反向建图,i从1到n,开始深搜dfs( i ),对i点的边,由小到大继续搜一下,同时标记搜过的数,搜过之后就不再搜,搜到底之后ans[cnt++] = u;这样顺序输出就是答案,后来经过超哥指点,才明白深搜贪心是错的.只有 反向建图,用优先队列把较大的数尽量排在前面,然后反序输出才是正解.. 1 #include<iostream> 2 #include<