NOIP2016 总结

今年的NOIP提高组还是有很大难度的,至少我认为这样QAQ;

实际证明只是搞掉了D1T1,剩下的都是骗分???

D1 T1 玩具谜题:

这道题相对简单,根据题意进行模拟即可;

考试时忘了写: if(tmp==0) tmp=n; 貌似要掉好多分?;

#include<cstdio>
#include<cstring>
#include<algorithm>
using  namespace std;
struct your
{
    int to;
    char s[20];
}a[110000];
int n,m;
int tmp=1;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%s",&a[i].to,a[i].s);
    }
    for(int i=1;i<=m;i++)
    {
        int dx,dy;
        scanf("%d%d",&dx,&dy);
        if(dx==1)
        {
            if(a[tmp].to==0)tmp=(tmp+dy+n)%n;
            else tmp=(tmp-dy+n)%n;
        }
        else
        {
            if(a[tmp].to==0)tmp=(tmp-dy+n)%n;
            else tmp=(tmp+dy+n)%n;
        }
        if(tmp==0)tmp=n;
    }
    printf("%s",a[tmp].s);
}

D1 T2 天天爱跑步

一名蒟蒻不会正解......据说骗分正解是DFS寻径???然而我用的O(n^2)暴力和他们用DFS的一样多啊......

考场骗分代码在此:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m;
struct your
{
	int x,y;
}a[100100];
struct my
{
	int x,y;
}b[100100];
int t[100100];
int temp[1000];
int ans[100100];
int checklian()
{
	for(int i=1;i<=n-1;i++)
		if(abs(a[i].x-a[i].y)!=1) return 0;
	return 1;
}
void worklian()
{
	for(int i=1;i<=m;i++)
	{
		int dx,dy;
		scanf("%d%d",&dx,&dy);
		for(int j=1;j<=n;j++)
			if(dy>=dx&&j<=dy&&j>=dx&&t[j]==j-dx)
				ans[j]++;
			else 
				if(dy<=dx&&j>=dy&&j<=dx&&t[j]==dx-j)
					ans[j]++;
	}
	for(int i=1;i<=n;i++)
		printf("%d ",ans[i]);
	return ;
}
int checkt0()
{
	for(int i=1;i<=n;i++)
		if(t[i]!=0)return 0;
	return 1;
}
void workt0()
{
	int dx,dy;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&dx,&dy);
		for(int j=1;j<=n;j++)
			if(j==dx) ans[j]++;
	}
	for(int i=1;i<=n;i++)
		printf("%d ",ans[i]);
	return ;
}
int checkdst()
{
	for(int i=1;i<=m;i++)
		if(b[i].x!=b[i].y) return 0;
	return 1;
}
void workdst()
{
	for(int i=1;i<=m;i++)
		temp[b[i].x]++;
	for(int i=1;i<=n;i++)
		if(t[i]==0)ans[i]+=temp[i];
	for(int i=1;i<=n;i++)
		printf("%d ",ans[i]);
	return;
}
void workputong()
{
	for(int i=1;i<=m;i++)
		scanf("%d%d",&b[i].x,&b[i].y);
	if(checkdst()) workdst();
	else printf("2 0 0 1 1 1");
	return ;
}
int main()
{
	freopen("running.in","r",stdin);
	freopen("running.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n-1;i++)
		scanf("%d%d",&a[i].x,&a[i].y);
	for(int i=1;i<=n;i++)
		scanf("%d",&t[i]);
	if(checklian()) worklian();
	else if(checkt0()) workt0();
	else workputong();
	fclose(stdin);
	fclose(stdout);
	return 0;
}

D1 T3 换教室

Floyed+DP??? 然而考场写挂了?;

(有待完善)

D2 T1 组合数问题

考场上没想到正解,就硬生生的循环求阶乘,搞了点优化,貌似拿了不少分?;
比赛后才意识到竟然有组合数公式??
愧对于LLQ啊 其实可以做的更好,比如说可以加入快速幂优化,边乘边模,还傻乎乎的先把分子算出来再判断......

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int t,k,n,m;
long long jisuan1(long long x,long long y)
{
    long long p=1;
    for(int i=x;i<=y;i++) p*=i;
    return p;
}
long long jisuan2(int x)
{
    long long p=1;
    for(int i=1;i<=x;i++) p*=i;
    return p;
}
int main()
{
    freopen("problem.in","r",stdin);
    freopen("problem.out","w",stdout);
    scanf("%d%d",&t,&k);
    for(int z=1;z<=t;z++)
    {
        int ans=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=min(i,m)&&i!=j;j++)
            {
                if(j+1<=i-j)
                {
                    long long tmp=0;
                    tmp+=jisuan1(i-j+1,i);
                    if(tmp>=k&&tmp%k==0)
                    {
                        tmp/=jisuan2(j);
                        if(tmp%k==0&&tmp>=k) ans++;
                    }
                }
                else
                {
                    long long tmp=0;
                    tmp+=jisuan1(j+1,i);
                    if(tmp>=k&&tmp%k==0)
                    {
                        tmp/=jisuan2(i-j);
                        if(tmp%k==0&&tmp>=k) ans++;
                    }
                }
            }
        }
        printf("%d\n",ans);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

⬆ 考场上的代码

⬇ 正解是杨辉三角形+前缀和

#include<cstdio>
#include<algorithm>
using namespace std;
int a[2500][2500];
int f[2500][2500];
int t,k,n,m;
int main()
{
    scanf("%d%d",&t,&k);
    for(int i=1;i<=2000;i++)
        a[i][0]=a[0][i]=1;
    for(int i=1;i<=2010;i++)
        for(int j=1;j<=i;j++)
        {
            a[i][j]=(a[i-1][j-1]+a[i-1][j])%k;
            if(!a[i][j])f[i][j]=1;
        }
    for(int i=1;i<=2000;i++)
        for(int j=1;j<=2000;j++)
            f[i][j]=f[i][j]+f[i-1][j]+f[i][j-1]-f[i-1][j-1];
    for(int i=1;i<=t;i++)
 `      scanf("%d%d",&n,&m),printf("%d\n",f[n][m]);
}

D2 T2 蚯蚓

当时考场上也没有什么太好的思路,只好骗了20分;
回来之后看到的正解如下:这道题需要开三个队列,一个数列存初始的蚯蚓,另外两个数列分别求切下蚯蚓的较长部分和较短部分,保持每个队列的单调递减,我听从了学长的建议,使用数组模拟队列。然后对于++q的问题,使用前缀和思想;

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[4][7510000];
int l[4],r[4];
int n,m,qsum,u,v,t;
int sum;
int cmp(int x,int y)
{
    return x>y;
}
int findmax()
{
    int maxi,maxx=-2001000000;
    if(l[1]<=r[1]&&maxx<a[1][l[1]]) maxx=a[1][l[1]],maxi=1;
    if(l[2]<=r[2]&&maxx<a[2][l[2]]) maxx=a[2][l[2]],maxi=2;
    if(l[3]<=r[3]&&maxx<a[3][l[3]]) maxx=a[3][l[3]],maxi=3;
    l[maxi]++;
    return maxx;
}
void shuchu()
{
	int k=0;
    for(int i=1;i<=n+m;i++)
    {
        int nmp=findmax()+sum;
        if(i%t==0) printf("%d",nmp);
    }
    return ;
}
void work()
{
	int k=0;
    long long temp1,temp2;
    for(int i=1;i<=m;i++)
    {
        long long nmp=findmax();
        nmp+=sum;
        sum+=qsum;
        temp1=nmp*u/v;
		temp2=nmp-nmp*u/v;      
		a[2][++r[2]]=max(temp1,temp2)-sum;
        a[3][++r[3]]=min(temp1,temp2)-sum;
        if(i%t==0) printf("%lld",nmp);
    }
    printf("\n");
    shuchu();
    return ;
}
int main()
{
    l[1]=l[2]=l[3]=1;
    scanf("%d%d%d%d%d%d",&n,&m,&qsum,&u,&v,&t);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[1][++r[1]]);
    sort(a[1]+1,a[1]+r[1]+1,cmp);    
    work();
}

D2 T3 愤怒的小鸟

状压DP??? 不会啊

现在会了

首先贪心 打一只也是打 打两只也是打 那么我们就要预处理出 f[i][j] 即包含i,j猪能打掉的猪的集合
然后DP

dp[s|f[i][j]]=min(dp[s|f[i][j]],dp[s]+1); dp[s|(1<<(i-1))]=min(dp[s|(1<<(i-1)],dp[s]+1);

但是会TLE 那我们就这样 找到第一只没有被打掉的猪(i) 然后再枚举j进行DP转移

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
int time;
int n,m;
int f[200][020];
int dp[2621500];
struct your
{
	double x,y;
}a[200]; 
double calc_a(double aa,double bb,double cc,double dd)
{
	return ((dd/cc)-(bb/aa))/(cc-aa);
}
double calc_b(double tmp,double aa,double bb)
{
	return (bb/aa)-tmp*aa;
}
double Fabs(double tmp)
{
	return (tmp>0)?tmp:-tmp;
}
int main()
{
	scanf("%d",&time);
	while(time)
	{
		time--;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)
			scanf("%lf%lf",&a[i].x,&a[i].y);
		for(int i=1;i<=n;i++)
			for(int j=i+1;j<=n;j++)
			{
				double dx=calc_a(a[i].x,a[i].y,a[j].x,a[j].y);
				double dy=calc_b(dx,a[j].x,a[j].y);
				if(dx>=0) continue; 
				for(int k=1;k<=n;k++)
					if(Fabs(dx*a[k].x*a[k].x+dy*a[k].x-a[k].y)<=1e-6)
						f[i][j]|=(1<<(k-1));
			}
		for(int i=0;i<=(1<<n);i++) dp[i]=233333333;
		dp[0]=0;
		for(int s=0;s<(1<<n);s++)
			for(int i=1;i<=n;i++)
				if(!(s&(1<<(i-1)))) 
				{
					dp[s|(1<<(i-1))]=min(dp[s|(1<<(i-1))],dp[s]+1);
					for(int j=i+1;j<=n;j++)
							dp[s|f[i][j]]=min(dp[s|f[i][j]],dp[s]+1);
					break;
				}
		printf("%d\n",dp[(1<<n)-1]);
		memset(f,0,sizeof f);
	}
	return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注