NOIP2017提高组解题报告

来源:互联网 发布:mac osx vmware tools 编辑:程序博客网 时间:2024/05/01 21:08

Day 1

T1:博主只拿了60pts exgcd,弱啊
正解其实就是a*b-a-b
这种题考场上一看数据范围应该打表测试一下,发现大概的规律再去证明
结论:对于正整数a,b满足gcd(a,b)=1,我们有ax+by=n无非负整数解的最大正整数n为ab-a-b
证明如下:
我们可以用反证法,假设存在ax+by=abab

a(x+1)+b(y+1)=ab

a|(y+1)b|(x+1)

令ak=y+1,bj=x+1
abj+abk=ab

ab(j+k)=ab

我们知道x,y>=0,那么那么有x+1>=1,y+1>=1
那么k>=1,j>=1,k+j>=2那个柿子不成立
所以假设错误,得证

#include <cstdio>using namespace std;int main(){    int a,b;    scanf("%d%d",&a,&b);    printf("%lld",(long long)a*b-a-b);}

T2:这种大模拟没有写对我也是挺服气自己了。。
思路没理清啊,栈空时才要更新最大值,我在里面就给更新最大值了,ta当然不对啊
son[i]表示i这一层包含的最大值
own[i]表示i这一层自己的值,要是根本进不去的话设成一个最大的负数吧
这样当栈空的时候取一个最大值看看等不等于一开始的

#include <cstdio>#include <cstring>#include <iostream>#define INF 1e9using namespace std;int ha[1005],stack[1200],num,own[1200],son[1200];char st[1200];int js(char st[]){    int i=0,b=0;    while (st[i]>='0' && st[i]<='9') b=b*10+st[i]-'0',i++;    return b;}int main(){    freopen("complexity.in","r",stdin);    freopen("complexity.out","w",stdout);    int T;    scanf("%d",&T);    while (T--)    {        int bb=0,b=0,n,i,vv=0;        scanf("%d",&n);        memset(ha,0,sizeof(ha));        memset(son,0,sizeof(son));        memset(own,0,sizeof(own));        num=0;        scanf("%s",st);        int ls=strlen(st);        if (n%2!=0) vv=1;        for (i=0;i<ls;i++)          if (st[i]=='(')          {            i++;            if (st[i]=='1') break;            else             {                while (st[i]!='^') i++;                i++;                while (st[i]>='0' && st[i]<='9') b=b*10+st[i]-'0',i++;                break;            }          }        for (i=1;i<=n;i++)        {            char ss[205],zm[205],f[205],e[205];            scanf("%s",ss);            if (ss[0]=='F')            {                scanf("%s%s%s",&zm,&f,&e);                if (ha[zm[0]])vv=1;                ha[zm[0]]=1;                if ((f[0]=='n' && e[0]!='n') || (f[0]!='n' && e[0]!='n' && js(f)>js(e))) own[++num]=-INF;                else if ((e[0]>='0' && e[0]<='9') || (f[0]=='n' && e[0]=='n')) own[++num]=0;                else own[++num]=1;                son[num-1]=max(own[num],son[num-1]);                stack[num]=zm[0];            }            else            {                if (!num)vv=1;                ha[stack[num]]=0;                own[num]+=son[num];                son[num-1]=max(own[num],son[num-1]);                son[num]=0; own[num]=0;                num--;                if (!num) bb=max(son[num],bb);            }             }          if (vv || num) {printf("ERR\n");continue;}        if (bb==b) printf("Yes\n");        else printf("No\n");     }    return 0;}

T3:Day1的dp。。
30pts暴力

Day 2

T1:各种数据都能过,被NOIP的数据卡了,竟然是因为精度开的太大了。。。1e-18就A了,好气哦
我用的是dij最短路判断O(n2)连边求就好了

#include <queue>#include <cmath>#include <cstdio>#include <cstring>#define LL long long using namespace std;const LL INF=1e18;const double eps=1e-18;const int N=1005;const int M=N*N;struct hh{int x,y,z;}ball[N];struct www{int id;LL z;}q[M+N];int tot,nxt[M],point[N],v[M],num;LL dis[N];int n,r,h,t;bool vis[N];bool operator <(const www &a,const www &b){return a.z<b.z;}void addline(int x,int y){    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;    ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;}void push(www now){    q[++num]=now;    int x=num,fa=x>>1;    while (fa && q[x]<q[fa])    {        swap(q[x],q[fa]);        x=fa; fa>>=1;    }}void pop(){    q[1]=q[num--];    int now=1,l=now<<1,r=now<<1|1,better=l;    if (r<=num && q[r]<q[l]) better=r;    while (better<=num && q[better]<q[now])    {        swap(q[better],q[now]);        now=better,l=now<<1,r=now<<1|1,better=l;        if (r<=num && q[r]<q[l]) better=r;    }}void dij(){    memset(dis,0x7f,sizeof(dis));    memset(vis,0,sizeof(vis));    dis[0]=0;    push((www){0,0});    while (num)    {        www now=q[1]; pop();         if (vis[now.id]) continue;        vis[now.id]=1;        for (int i=point[now.id];i;i=nxt[i])          if (dis[v[i]]>dis[now.id]+1)          {            dis[v[i]]=dis[now.id]+1;            push((www){v[i],dis[v[i]]});          }    }}bool jiao(int i,int j){    double dd=(double)sqrt((LL)(ball[i].x-ball[j].x)*(ball[i].x-ball[j].x)+(LL)(ball[i].y-ball[j].y)*(ball[i].y-ball[j].y)+(LL)(ball[i].z-ball[j].z)*(ball[i].z-ball[j].z));    if (dd<=(double)2*r || abs(dd-2*r)<=eps) return 1;    return 0;}int main(){    freopen("cheese.in","r",stdin);    freopen("cheese.out","w",stdout);    int T,i,j,nn;scanf("%d",&T);    while (T--)    {        tot=0; memset(point,0,sizeof(point));        scanf("%d%d%d",&nn,&h,&r);        t=nn+1;n=0;        for (i=1;i<=nn;i++)         {            ++n;            scanf("%d%d%d",&ball[n].x,&ball[n].y,&ball[n].z);            if ((ball[n].z-r>=h) || (ball[n].z+r<=0)) n--;        }        for (i=1;i<=n;i++)        {            if (ball[i].z+r>=h) addline(i,t);            for (j=i+1;j<=n;j++)              if (jiao(i,j)) addline(i,j);            if (ball[i].z-r<=0) addline(0,i);        }        dij();        if (dis[t]>INF) printf("No\n");else printf("Yes\n");     }}

T2:最弱的博主今年唯一A掉的题目
其实就是一个暴力啊,分了两部分来写来稳住40pts
我们可以用dp[i]表示i这个状态(二进制),其中1表示这个点经过了,0表示没有经过
再用f[i][j]表示i这个状态每个点到达j这个点的距离,然后暴力转移一波就好了
效率是O(n42n)看着很大对吧,可是这是极限效率,这个效率是今年跑的最快的做法辣

#include <queue>#include <cstdio>#include <cstring>#include <iostream>#define LL long longusing namespace std;const int N=2200;const LL INF=1e18;int tot,nxt[N],point[N],v[N],c[N],f[5000][15],h[N];LL dp[5000];bool vis[N];void addline(int x,int y,int z){    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;    ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; c[tot]=z;}void spfa(int x){    queue<int>q;    q.push(x);    while (!q.empty())    {        int now=q.front(); q.pop();        vis[now]=0;        for (int i=point[now];i;i=nxt[i])          if (h[v[i]]>h[now]+1)          {            h[v[i]]=h[now]+1;            if (!vis[v[i]]) vis[v[i]]=1,q.push(v[i]);          }    }}int main(){    int n,m,i,j,k,ii,num,lz=0,l;LL ans=INF;bool vv=1;    scanf("%d%d",&n,&m);    for (i=1;i<=m;i++)    {        int x,y,z;        scanf("%d%d%d",&x,&y,&z);        addline(x,y,z);if (lz!=z && i!=1) vv=0;        lz=z;    }    if (vv)    {        for (i=1;i<=n;i++)        {            memset(h,0x7f,sizeof(h));            memset(vis,0,sizeof(vis));h[i]=0;            spfa(i);LL qz=0;            for (j=1;j<=n;j++) qz+=h[j]*lz;            ans=min(ans,qz);        }    }    else    {    num=(1<<n)-1;    for (i=1;i<=n;i++)    {        memset(dp,0x7f,sizeof(dp));        dp[1<<i-1]=0;f[1<<i-1][i]=0;        for (j=0;j<=num;j++)          if (dp[j]<INF)           {            for (k=1;k<=n;k++)              if ((j>>k-1)&1)               {                for (ii=point[k];ii;ii=nxt[ii])                  if (!((j>>(v[ii]-1)&1)))                  {                    if (dp[j|(1<<(v[ii]-1))]>dp[j]+(LL)(f[j][k]+1)*c[ii])                    {                        dp[j|(1<<(v[ii]-1))]=dp[j]+(LL)(f[j][k]+1)*c[ii];                        for (l=1;l<=n;l++) f[j|(1<<(v[ii]-1))][l]=f[j][l];                        f[j|(1<<(v[ii]-1))][v[ii]]=f[j][k]+1;                    }                  }               }          }        ans=min(ans,dp[num]);    }    }    printf("%lld",ans);}

T3:waiting

原创粉丝点击