2019暑假正睿集训8.10day7题解及总结

T1 松

50pts~80pts

这道题直接暴力搜索,每次在三个符号中任选一个,按题意合并数。当合并了还剩两个数的时候,就判断它们选哪种符号最终能为1,找到一种ans+1

100pts

优化1:位运算。把输⼊串按照FFT初始化⽅法⼀样bitrev⼀ 下就可以⽤位运算优化。

优化2:四⽑⼦。当串⻓之后16的时候预处理。 ~~~~ 可能要稍微松⼀下,也可能不⽤。~~

为此我今天学了三个多小时的FFT(理解思路+代码实现)

其实学会后还挺简单的(看了无数篇题解后emmm)

就是把两个多项式相乘(即求卷积),直接乘的话复杂度是 O ( n 2 ) O(n^2) O(n2) 所以把多项式的系数表示转化成点值表示。

举个例子 f [ x ] = a 0 x 0 + a 1 x 1 + a 2 x 2 + . . . . . . a n x n f[x]=a_0x^0+a_1x^1+a_2x^2+......a_nx^n f[x]=a0x0+a1x1+a2x2+......anxn a i a_i ai 是每一项的系数,所以这是多项式f[x]的系数表示法

( x 0 , f [ x 0 ] ) (x_0,f[x_0]) (x0,f[x0]) $ (x_1,f[x_1])$ … ( x n , f [ x n ] ) (x_n,f[x_n]) xn,f[xn]) 则为多项式的点值表示法 相当于代入一些x的值,求出对应的y的值,而要代入的x的值的个数显然至少为n个才能确定一个多项式(可类比二元一次方程) 。

而对于多项式 f [ x ] ∗ g [ x ] f[x]*g[x] f[x]g[x]若它们x代入的是相同的数,那么就把算出对于的y值相乘就可以了

这是个总体的思路,还有非常多的细节部分实现,例如引入复数和单位跟,DFT和IDFT,二进制转换,递归和迭代两种方法等等,一时半会真的说不清楚,之后再详细写一篇有关于FFT的题解QWQ。

我写的是更为高效的迭代算法:

附上代码如下
#include<bits/stdc++.h>
using namespace std;
typedef complex<double> cp;
#define N 2097153
const double pie=acos(-1);
int n;
cp a[N],b[N];
int rev[N],ans[N];
char s1[N],s2[N];
int read(){
	int sum=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return sum*f;
}
void init(int k)
{
    int len=1<<k;
	for(int i=0;i<len;i++)
	rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
}
void fft(cp *a,int n,int flag){
    for(int i=0;i<n;i++)
	{
	  if(i<rev[i])swap(a[i],a[rev[i]]);
	}
	for(int h=1;h<n;h*=2)
	{
	cp wn=exp(cp(0,flag*pie/h));
	 for(int j=0;j<n;j+=h*2)
	 {
	  cp w(1,0);
	   for(int k=j;k<j+h;k++)
	   {
	     cp x=a[k];
	     cp y=w*a[k+h];
         a[k]=x+y;
         a[k+h]=x-y;
         w*=wn;
	   }
	 }
	 }
	 if(flag==-1)
	 for(int i=0;i<n;i++)
     a[i]/=n;
}
int main(){
	n=read();
	scanf("%s%s",s1,s2);
    for(int i=0;i<n;i++)a[i]=(double)(s1[n-i-1]-'0');
	for(int i=0;i<n;i++)b[i]=(double)(s2[n-i-1]-'0');
	int k=1,s=2;
 	while((1<<k)<2*n-1)k++,s<<=1;
	init(k);
    fft(a,s,1);
    fft(b,s,1);
    for(int i=0;i<s;i++)
    a[i]*=b[i];
    fft(a,s,-1);
    for(int i=0;i<s;i++)
    {
	ans[i]+=(int)(a[i].real()+0.5);
	ans[i+1]+=ans[i]/10;
	ans[i]%=10;
	}
	while(!ans[s]&&s>-1)s--;
	if(s==-1)printf("0");
	else
	for(int i=s;i>=0;i--)
	printf("%d",ans[i]);
	return 0;
}

T2 集合

80pts

枚举最⼩差,不妨设最⼩的数是0,进⾏⼀下简单的 dp。

100pts

枚举⼀下最⼩差d,那么数的个数不会超过n/d。

• 所以再枚举⼀下数的个数x,然后想办法算⼀下。

• ⽐如最⼩数是c,那么⽅案数可能是 ( n − c − ( d − 1 ) ∗ ( x − 1 ) , x − 1 ) (n-c-(d-1)*(x-1),x-1) (nc(d1)(x1),x1)

• 通过⼀些简单的凑配就可以 O ( 1 ) O(1) O(1)完成求和。

T3 最短路

这道题说实话我真没听懂,老师的题解就下面一句话(只可意会emmm)

观(cai)察(ce)可得每个点都只会往上⾛,并且经过的不超过 O(log n)个,暴⼒做法是把这些块都找出来,然后bfs即可。

在这里插入图片描述

今日总结

1.第一题暴力拿了50分,有点超出预料,以为只有30分。但其实优化一下80应该没问题的。

2.第二题也是暴搜得了20分 (暴力碾标算,搜索过百万)

3.感觉这几天比刚开始好些了,至少拿到了该拿的暴力分

4.疾风知劲草,岁寒见后凋。加油。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值