2021-01-25纪中模拟赛总结
T1 【NOIP2016提高组复赛】†组合数问题
题目传送门
想法
这道题没什么难度,首先手推一下C(0,0)到C(4,4),不难发现这是一个杨辉三角.
所以用一个矩阵暴枚就完了?!
事实证明,你想太多,n<=2000,m<=2000.你暴力枚举直接存,不炸掉才怪。
那怎么办呢?
首先观察题目,发现k是不变的,而我们又知道(a+b)%k=(a%k+b%k)%k.
那么我们在算杨辉三角时给每个数%k一下,这不就不会炸了?
这时候我们可以发现一个更神奇的东西:杨辉三角上(i,j)如果为0,那么不就代表着C(i,j)%k也为0吗。
这时候答案显而易见了,我们用二维前缀和来维护一下某个位置在它前面有多少个地方为0,最后输出相应位置的值就好了。
AC代码
#include<iostream>
#include<cstdio>
using namespace std;
long long map[3001][3001],ans[3001][3001],x[100001],y[100001],qzh[3001][3001];
int main()
{
freopen("problem.in","r",stdin);
freopen("problem.out","w",stdout);
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&x[i],&y[i]);
}
for(int i=0;i<=3000;i++)
{
for(int j=0;j<=i;j++)
{
if(j==0)
{
map[i][j]=1;
}
else
{
map[i][j]=(map[i-1][j]+map[i-1][j-1])%k;
}
}
}
for(int i=1;i<=3000;i++)
{
for(int j=1;j<=i;j++)
{
qzh[i][j]=qzh[i-1][j]+qzh[i][j-1]-qzh[i-1][j-1];
if(map[i][j]==0)
{
qzh[i][j]++;
}
}
for(int j=i+1;j<=3000;j++)
{
qzh[i][j]=qzh[i][j-1];
}
}
long long e;
for(int i=1;i<=n;i++)
{
e=min(x[i],y[i]);
printf("%d\n",qzh[x[i]][e]);
}
}
T2 【NOIP2017提高组正式赛】奶酪
题目传送门
想法
我们知道,如果一个空洞可以走到上表面,那么可以走到这个空洞的洞也可以走到上表面,根据这一点,不难想到,我们可以先求出哪些空洞可以走到上表面,再求哪些空洞可以走到这些洞,这样子一层层向下找,给找到的点打上标记,最后看看和下表面直接接触的点有没有被打上标记的,如果有便输出“Yes”,不然就输出“No”。
AC代码
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
double x[100001],y[100001],z[100001];
int map[1001][1001],len[2001],st[10001],en[10001],bz[2001];
double dist(int i,int j)
{
return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])+(z[i]-z[j])*(z[i]-z[j]));
}
void dg(int x)
{
bz[x]=1;
for(int i=1;i<=len[x];i++)
{
if(bz[map[x][i]]!=1)
{
dg(map[x][i]);
}
}
}
int main()
{
freopen("cheese.in","r",stdin);
freopen("cheese.out","w",stdout);
int t;
cin>>t;
int n,p,q,u;
double h,r;
for(int tem=1;tem<=t;tem++)
{
cin>>n>>h>>r;
p=0;
q=0;
u=0;
for(int i=1;i<=n;i++)
{
bz[i]=0;
len[i]=0;
}
for(int i=1;i<=n;i++)
{
cin>>x[i]>>y[i]>>z[i];
if(abs(z[i])<=r)
{
p++;
st[p]=i;
}
if(abs(z[i]-h)<=r)
{
q++;
en[q]=i;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(dist(i,j)<=r*2)
{
if(i!=j)
{
len[i]++;
map[i][len[i]]=j;
len[j]++;
map[j][len[j]]=i;
}
}
}
}
for(int i=1;i<=q;i++)
{
dg(en[i]);
}
for(int i=1;i<=p;i++)
{
if(bz[st[i]]==1)
{
cout<<"Yes"<<endl;
u=1;
break;
}
}
if(u==0)
{
cout<<"No"<<endl;
}
}
}
T3【NOIP2016提高组复赛】愤怒的小鸟
题目传送门
想法
解出相邻两猪的参数,再用状压DP来求覆盖所有猪最小要多少条曲线
AC代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
double x[101],y[101];
int f[1000001],g[101][101];
int main()
{
freopen("angrybirds.in","r",stdin);
freopen("angrybirds.out","w",stdout);
int t;
cin>>t;
int n,tem;
double p,q;
while(t--)
{
cin>>n>>tem;
for(int i=0;i<n;i++)
{
cin>>x[i]>>y[i];
}
memset(f,63,sizeof(f));
memset(g,0,sizeof(g));
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(i!=j)
{
p=(y[i]/x[i]-y[j]/x[j])/(x[i]-x[j]);
q=(x[i]/x[j]*y[j]-x[j]/x[i]*y[i])/(x[i]-x[j]);
if(p<=-1e-6)
{
for(int k=0;k<n;k++)
{
if(fabs(p*x[k]*x[k]+q*x[k]-y[k])<=1e-6)
{
g[i][j]|=1<<k;
}
}
}
}
}
g[i][i]|=1<<i;
}
f[0]=0;
for(int i=0;i<(1<<n);i++)
{
for(int j=0;j<n;j++)
{
if(!((1<<j)&i))
{
for(int k=j;k<n;k++)
{
if(!((1<<k)&i))
{
f[i|g[j][k]]=min(f[i|g[j][k]],f[i]+1);
}
}
break;
}
}
}
cout<<f[(1<<n)-1]<<endl;
}
}