【LGR-069】洛谷 2 月月赛 II & EE Round 2 Div.2 A-C题解

洛谷2月月赛前三题题解。

T1:由最优性可知,我们每次一定要选出现最多次的字符进行操作,因此我们只需要找原始字符串中出现次数最多的字符,不停对其进行变换,直到其长度符合要求。

注意数据类型问题,由于变换的时候可能会超出$unsigned long long$的上限,因此我们需要判断其是否溢出。

 1 #include<iostream>
 2 #include<queue>
 3 #include<cstdio>
 4 #include<cstring>
 5 #define int unsigned long long
 6 #define N 1000005
 7 using namespace std;
 8 int n,ch[1005],l,ans,maxn;
 9 char str[N];
10 signed main()
11 {
12     ios::sync_with_stdio(0);
13     cin>>(str+1);
14     cin>>l;
15     n=strlen(str+1);
16     for(int i=1;i<=n;i++)ch[str[i]]++;
17     for(int i=0;i<=255;i++)maxn=max(maxn,ch[i]);
18     while(n<l)
19     {
20         ans++;
21         if((n+maxn)<n)break;
22         n+=maxn;
23         maxn*=2;
24     }
25     cout<<ans<<endl;
26     return 0;
27 }
28  

T2:我认为这是本场比赛出的最好的题。

下面先说几个部分分的做法。

$Subtask 1$直接输出样例不解释。

$Subtask 2$枚举$i$,$j$,$k$,$l$,$O(n^4)$暴力计算即可。

$Subtask 3,4$这两个部分分是可以一起做的,也是考场上比较好想的。观察数据范围可知,值域很小,因此考虑直接统计。

为了方便说明,我们先记值域为$m$

预处理一个数组$F$,$F_i$表示$i$在这个数列中出现了多少次。根据$F$数组初步统计$or$和$and$和。同样,设$B_i$表示i这个数是多少对数的$or$值,$C$同理,只需简单的乘法原理即可算出这两个数组。

最后直接枚举统计即可。时间复杂度$O(m^2)$

正解:上面的那个方法看起来很牛逼,但是值域一大它就完了。

因此考虑位运算的性质。

位运算的操作实际上位与位之间是相互独立的,并不会互相影响。

对于每一位,我们手算出16种可能性,发现以下这些四元组$(i,j,k,l)$可以通过题目中的位运算操作得到$1$

$(1,1,0,0),(1,0,1,0),(1,0,0,1),(0,1,0,1),(0,1,1,0),(0,0,1,1),(1,1,1,0),(1,1,0,1),(1,0,0,0),(0,1,0,0)$

然后开个二维数组$cnt$,其中$cnt(i,j)$表示第i位为j的数的个数。

乘法原理计算出该位为$1$的情况数后乘上位权,相加即可。

别忘记取模!!!

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define N 5000005
 5 using namespace std;
 6 int read()
 7 {
 8     int x=0,f=1;char ch=getchar();
 9     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
10     while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
11     return x*f;
12 }
13 unsigned int n,a[N],cnt[N][2],maxx,maxy,maxn,f[N];
14 unsigned int ans=0;
15 signed main()
16 {
17     n=read();
18     for(int i=1;i<=n;i++)
19     {
20         a[i]=read();
21         for(int j=0;j<32;j++)
22         {
23             if(a[i]&(1<<j))cnt[j][1]++;
24             else cnt[j][0]++;
25         }
26     }
27     for(int i=0;i<32;i++)
28     {
29         int res=0;
30         res+=(long long)(cnt[i][1]*cnt[i][1]*cnt[i][0]*cnt[i][0])*6;
31         res+=(long long)(cnt[i][1]*cnt[i][1]*cnt[i][1]*cnt[i][0])*2;
32         res+=(long long)(cnt[i][1]*cnt[i][0]*cnt[i][0]*cnt[i][0])*2;
33         ans+=(1<<i)*res;
34     }
35     cout<<ans<<endl;
36     return 0;
37 }

T3:很烦人的dp。

就这东西让我$270->170$(分数)。

我考场上第一反应:

$f[i][0/1/2/3]$表示长度为i的字符串,以;)]}为结尾的"语句"有多少个
$g[i][0/1/2/3]$表示长度为i的字符串,以;)]}为结尾的"程序片段"有多少个
$h[i][0/1/2/3]$表示长度为i的字符串,以;)]}为结尾的"语句块"有多少个
$q[i][0/1/2/3]$表示长度为i的字符串,以;)]}为结尾的"函数"有多少个
$w[i][0/1/2/3]$表示长度为i的字符串,以;)]}为结尾的"值"有多少个

然后对应转移。

结果7那个样例我输出141,当场心态崩掉。

发现离结束只有10分钟

然后就自闭了。

赛后,伟大的$4404$同志帮我找到了问题:

考虑如下字符串:([]{});

然后你会发现这可以通过两种方法构得。

究其原因,是因为$A$是函数,所以$A$是个值,所以$(A)$是个函数也是个值。

所以"值"更新的时候无需再加一遍"函数"

然后AC之后发现,第二维没卵用。

自闭了。

233333333333333333333333333333333333333~~~~

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define int unsigned long long
 5 #define N 1000006
 6 using namespace std;
 7 int n,f[N],g[N],h[N],q[N],w[N],ans;
 8 signed main()
 9 {
10     cin>>n;
11     f[1]=1;
12     g[0]=1;
13     for(int i=1;i<=n;i++)
14     {
15         if(i>1)q[i]+=h[i-2];
16         if(i>3)q[i]+=h[i-4];
17         if(i>1)q[i]+=q[i-2];
18         w[i]+=q[i];
19         if(i>1)w[i]+=w[i-2];
20         if(i>1)h[i]+=g[i-2];
21         f[i]+=w[i-1];
22         f[i]+=h[i];
23         for(int j=0;j<=i;j++)g[i]+=g[j]*f[i-j];
24     }
25     cout<<g[n]<<endl;
26 }

猜你喜欢

转载自www.cnblogs.com/szmssf/p/12315579.html
今日推荐