平安夜的hu测
mdzz最近就是有点颓,明知道这次成绩要上报,还是妥妥的爆了零。。。
这份题的暴力打满了就是170。。。
T1
分析:
%60
做这道题之前,要了解一些复数运算
手玩了r的1~8次方之后,发现i前面一定会有一个sqrt(7),而常数项中一定没有sqrt(7)
实际上这就是复数的计算法则:
而我们需要求的答案也是符合这个形式的(只有i前面有sqrt(7))
那我们就可以把i前面的sqrt(7)抹掉
(但是如果遇到sqrt(7)i*sqrt(7)i,我们需要替换成-7)
预处理r^23所有的a+bi中的a和b值
之后暴力搜索
这里有一个小细节:
因为状态只有01,为了降低常数,我们可以直接用二进制枚举
这是一种很重要的思想
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
double x,y;
double a[30],b[30];
int num[30];
bool ff=0;
void cal(int i,int j,int k)
{
a[k]=a[i]*a[j]-7*b[i]*b[j]; //b中都有一个sqrt(7),所以要替换成-7
b[k]=b[i]*a[j]+a[i]*b[j];
}
int pd(int num)
{
double xx=0,yy=0;
for (int i=0;i<24;i++)
if (num&(1<<i)) xx+=a[i],yy+=b[i];
return xx==x&&yy==y;
}
int main()
{
freopen("verlauf.in","r",stdin);
freopen("verlauf.out","w",stdout);
scanf("%lf%lf",&x,&y);
a[0]=1.0; b[0]=0.0;
a[1]=-0.5; b[1]=0.5;
for (int i=2;i<30;i++)
{
if (i&1) cal(i-1,1,i);
else cal(i/2,i/2,i);
}
for (int i=0;i<(1<<24);i++) //8388608
if (pd(i))
{
for (int j=0;j<24;j++)
if (i&(1<<j)) printf("%d ",j);
break;
}
return 0;
}
T2
T3
分析:
40%
实际上这道题的部分分比较好想
什么都别多想,直接O(nk^2)
设计状态f[i][j],表示第i位上的数字是j的方案数
枚举每一位上的数字,判断相邻两数之间的gcd
直接计数即可
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
const ll p=1000000007;
const int N=1000010;
int a[N],n,K;
int gcd[1002][1002];
ll ans=0,f[1002][1002];
int GCD(int a,int b)
{
int r=a%b;
while (r)
{
a=b;b=r;
r=a%b;
}
return b;
}
int main()
{
freopen("geburtstag.in","r",stdin);
freopen("geburtstag.out","w",stdout);
for (int i=1;i<=1000;i++)
for (int j=1;j<=i;j++)
gcd[i][j]=gcd[j][i]=GCD(i,j);
scanf("%d%d",&n,&K);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=a[1];i++) f[1][i]=1;
for (int i=2;i<=n;i++)
for (int j=1;j<=a[i-1];j++)
for (int k=1;k<=a[i];k++)
if (gcd[j][k]<=K)
f[i][k]=(f[i][k]%p+f[i-1][j]%p)%p;
for (int i=1;i<=a[n];i++) ans=(ans+f[n][i]%p)%p;
printf("%lld",ans);
return 0;
}