[NOIP补坑计划]NOIP2017 题解&做题心得

终于做完了……

场上预计得分:?(省一分数线:295)

由于看过部分题解所以没有预计得分qwq

题解:

D1T1 小凯的疑惑

题面

震惊!一道小学奥数题竟难倒无数高中考生!

欢迎大家以各种姿势*和谐*出题人

证明见这篇博客

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<queue>
 7 #include<map>
 8 #define inf 2147483647
 9 #define eps 1e-9
10 using namespace std;
11 typedef long long ll;
12 ll a,b;
13 int main(){
14     scanf("%lld%lld",&a,&b);
15     printf("%lld",a*b-a-b);
16     return 0;
17 }

D1T2 时间复杂度

题面

细节太多就不说了……我的代码应该是loj上最丑的

要特别注意的几个点:

1.不被执行的循环内可能会有语法错误;

2.要判断x=y=n的情况;

3.可能会开头没有F直接E;

4.看代码吧……

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<queue>
 7 #include<stack>
 8 #include<map>
 9 #define inf 2147483647
10 #define eps 1e-9
11 using namespace std;
12 typedef long long ll;
13 int t,l,x,t1,t2,nd,las,cnt,mx,top,st[101],nam[101];
14 char s[101];
15 bool ch,err,run,nm[26],ntrun[101];
16 int main(){
17     scanf("%d",&t);
18     while(t--){
19         memset(nm,0,sizeof(nm));
20         memset(nam,0,sizeof(nam));
21         memset(ntrun,0,sizeof(ntrun));
22         err=ch=false;
23         run=true;
24         mx=t1=t2=x=top=cnt=0;
25         las=-1;
26         scanf("%d%s",&l,s+1);
27         for(int i=1,ii=strlen(s+1);i<=ii;i++){
28             if(s[i]=='n')ch=true;
29             if(isdigit(s[i]))x=x*10+s[i]-'0';
30         }
31         if(x==1&&!ch)nd=0;
32         else nd=x;
33         for(int i=1;i<=l;i++){
34             scanf("%s",s+1);
35             if(s[1]=='F'){
36                 scanf("%s",s+1);
37                 if(!nm[s[1]-'a'])nm[s[1]-'a']=true,nam[i]=s[1]-'a';
38                 else err=true;
39                 t1=t2=0;
40                 scanf("%s",s+1);
41                 if(s[1]=='n')t1=101;
42                 else for(int i=1;i<=strlen(s+1);i++)t1=t1*10+s[i]-'0';
43                 scanf("%s",s+1);
44                 if(s[1]=='n')t2=101;
45                 else for(int i=1;i<=strlen(s+1);i++)t2=t2*10+s[i]-'0';
46                 if((t1!=101&&t2!=101&&t1>t2)||(t1==101&&t2<101)){
47                     if(run){
48                         run=false;
49                         las=i;
50                     }
51                 }
52                 st[++top]=i;
53                 if(run&&t1!=t2&&t2==101)cnt++;
54                 else ntrun[i]=true;
55                 mx=max(mx,cnt);
56             }else{
57                 if(top){
58                     if(run&&!ntrun[st[top]])cnt--;
59                     if(st[top]==las){
60                         las=-1;
61                         run=true;
62                     }
63                     nm[nam[st[top]]]=false;
64                     top--;
65                 }else err=true;
66             }
67         }
68         if(top)err=true;
69         if(err)puts("ERR");
70         else puts(mx==nd?"Yes":"No");
71     }
72     return 0;
73 }

D1T3 逛公园

题面

听说SPFA会被卡?吓得我写了个dij……

显然是计数dp,设$dis[i]$表示i到终点的最短路,$f[i][k]$表示点i到终点距离小于等于$dis[i]+k$的方案数,记忆化搜索就好了……

如果一个状态同时出现多次则说明有零环无解;

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<vector>
 6 #include<cmath>
 7 #include<queue>
 8 #include<stack>
 9 #include<map>
10 #define inf 2147483647
11 #define eps 1e-9
12 using namespace std;
13 typedef long long ll;
14 typedef pair<int,int> pii;
15 struct edge{
16     int v,w,next;
17 }a[500001],_a[500001];
18 int t,n,m,k,p,u,v,w,tot=0,_tot=0,head[100001],_head[100001],f[100001][51],dis[100001];
19 bool used[100001],ch[100001][51];
20 void add(int u,int v,int w){
21     a[++tot].v=v;
22     a[tot].w=w;
23     a[tot].next=head[u];
24     head[u]=tot;
25 }
26 void _add(int u,int v,int w){
27     _a[++_tot].v=v;
28     _a[_tot].w=w;
29     _a[_tot].next=_head[u];
30     _head[u]=_tot;
31 }
32 void dij(int vs){
33     priority_queue<pii,vector<pii>,greater<pii> >q;
34     dis[vs]=0;
35     q.push(pii(0,vs));
36     while(!q.empty()){
37         int u=q.top().second;
38         q.pop();
39         if(used[u])continue;
40         used[u]=true;
41         for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
42             int v=a[tmp].v;
43             if(dis[v]>dis[u]+a[tmp].w){
44                 dis[v]=dis[u]+a[tmp].w;
45                 q.push(pii(dis[v],v));
46             }
47         }
48     }
49 }
50 int work(int x,int k){
51     if(ch[x][k])return -1;
52     if(f[x][k])return f[x][k];
53     ch[x][k]=true;
54     if(x==n)f[x][k]=1;
55     for(int tmp=_head[x];tmp!=-1;tmp=_a[tmp].next){
56         int v=_a[tmp].v,nw=dis[v]-dis[x]+_a[tmp].w;
57         if(nw<=k){
58             int t=work(v,k-nw);
59             if(t==-1)return f[x][k]=-1;
60             f[x][k]=(f[x][k]+t)%p;
61         }
62     }
63     ch[x][k]=false;
64     return f[x][k];
65 }
66 int main(){
67     scanf("%d",&t);
68     while(t--){
69         tot=_tot=0;
70         memset(used,0,sizeof(used));
71         memset(f,0,sizeof(f));
72         memset(ch,0,sizeof(ch));
73         memset(head,-1,sizeof(head));
74         memset(_head,-1,sizeof(_head));
75         memset(dis,0x3f,sizeof(dis));
76         scanf("%d%d%d%d",&n,&m,&k,&p);
77         for(int i=1;i<=m;i++){
78             scanf("%d%d%d",&u,&v,&w);
79             add(v,u,w);
80             _add(u,v,w);
81         }
82         dij(n);
83         printf("%d\n",work(1,k)%p);
84     }
85     return 0;
86 }

D2T1 奶酪

题面

裸bfs水题送温暖~

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<vector>
 6 #include<cmath>
 7 #include<queue>
 8 #include<stack>
 9 #include<map>
10 #define inf 2147483647
11 #define eps 1e-9
12 using namespace std;
13 typedef long long ll;
14 struct edge{
15     ll v,next;
16 }a[500001];
17 ll t,n,h,r,tot=0,x[1001],y[1001],z[1001],up[1001],dn[1001],head[1001];
18 bool ok,isin[1001];
19 void add(ll u,ll v){
20     a[++tot].v=v;
21     a[tot].next=head[u];
22     head[u]=tot;
23 }
24 bool bfs(){
25     queue<ll>q;
26     memset(isin,0,sizeof(isin));
27     for(ll i=1;i<=n;i++){
28         if(dn[i]){
29             q.push(i);
30             isin[i]=true;
31         }
32     }
33     while(!q.empty()){
34         ll u=q.front();
35         q.pop();
36         for(ll tmp=head[u];tmp!=-1;tmp=a[tmp].next){
37             ll v=a[tmp].v;
38             if(up[v])return true;
39             if(!isin[v]){
40                 q.push(v);
41                 isin[v]=true;
42             }
43         }
44     }
45     return false;
46 }
47 int main(){
48     scanf("%lld",&t);
49     while(t--){
50         memset(head,-1,sizeof(head));
51         memset(up,0,sizeof(up));
52         memset(dn,0,sizeof(dn));
53         tot=0;
54         ok=false;
55         scanf("%lld%lld%lld",&n,&h,&r);
56         for(ll i=1;i<=n;i++){
57             scanf("%lld%lld%lld",&x[i],&y[i],&z[i]);
58             if(z[i]<=r)dn[i]=true;
59             if(z[i]>=h-r)up[i]=true;
60             if(dn[i]&&up[i])ok=true;
61         }
62         if(ok){
63             puts("Yes");
64             continue;
65         }
66         for(ll i=1;i<n;i++){
67             for(ll j=i+1;j<=n;j++){
68                 if((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])+(z[i]-z[j])*(z[i]-z[j])<=r*r*4){
69                     add(i,j);
70                     add(j,i);
71                 }
72             }
73         }
74         puts(bfs()?"Yes":"No");
75     }
76     return 0;
77 } 

D2T2 宝藏

题面

看到数据范围肯定就是搜索或者状压DP了……听说记忆化搜索可以艹过去?

题解Orzxfz

设$f[i][s]$表示当前深度为i,已经访问过的点的状态为s,则$f[i][s]=min\{t∈s | f[i-1][t]+i*get(t,s\oplus t)\}$,其中$get(x,y)$表示集合y中所有点都向x中连边的最小代价;

枚举子集转移就好了,时间复杂度$O(n^23^n)$

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<vector>
 6 #include<cmath>
 7 #include<queue>
 8 #include<stack>
 9 #include<map>
10 #define inf 0x7f7f7f7f
11 #define eps 1e-9
12 #define lb(x) (x&-x)
13 using namespace std;
14 typedef long long ll;
15 ll n,m,ans=inf,u,v,w,d[15][15],f[15][10001],lg[10001];
16 ll get(ll x,ll y){
17     ll ret=0,tmp;
18     for(ll i=y;i;i-=lb(i)){
19         tmp=inf;
20         for(ll j=x;j;j-=lb(j)){
21             tmp=min(tmp,d[lg[lb(i)]][lg[lb(j)]]);
22         }
23         ret+=tmp;
24     }
25     return ret;
26 }
27 int main(){
28     memset(d,0x7f,sizeof(d));
29     memset(f,0x7f,sizeof(f));
30     for(int i=0;i<=12;i++)lg[1<<i]=i;
31     scanf("%lld%lld",&n,&m);
32     for(ll i=1;i<=m;i++){
33         scanf("%lld%lld%lld",&u,&v,&w);
34         u--,v--;
35         d[v][u]=d[u][v]=min(d[u][v],w);
36     }
37     if(n==1)return puts("0"),0;
38     for(ll i=0;i<n;i++){
39         f[0][1<<i]=0;
40     }
41     for(ll i=1;i<n;i++){
42         for(ll s=1;s<(1<<n);s++){
43             for(ll t=s;t;t=s&(t-1)){
44                 f[i][s]=min(f[i][s],f[i-1][t]+i*get(t,s^t));
45             }
46         }
47     }
48     for(ll i=0;i<n;i++){
49         ans=min(ans,f[i][(1<<n)-1]);
50     }
51     printf("%lld",ans);
52     return 0;
53 }

D2T3 列队

题面

这题标志着log级数据结构正式进入noip!(orzlxl)

splay的做法很明显……但是不好写并且€€£老爷机会卡常……

正解是对每一行和最后一列开一个线段树,每次$(x,y)$出队就找到第x行找到第y个未被使用的值(类似第k大),再从最后一列的那个线段树中找到第x个值放到第x行末尾,最后把开始找到的那个值放到最后一列末尾即可;

注意$y=m$时要特判,线段树要动态开点;

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<vector>
 6 #include<cmath>
 7 #include<queue>
 8 #include<stack>
 9 #include<map>
10 #define inf 0x7f7f7f7f
11 #define eps 1e-9
12 #define lb(x) (x&-x)
13 #define N 800000
14 using namespace std;
15 typedef long long ll;
16 struct node{
17     ll v;
18     int ls,rs;
19 }t[10000001];
20 int n,m,q,x,y,cnt=0,rts[600001];
21 vector<ll>v[600001];
22 void updata(int l,int r,int &u,int p){
23     if(!u)u=++cnt;
24     t[u].v++;
25     if(l==r)return;
26     int mid=(l+r)/2;
27     if(p<=mid)updata(l,mid,t[u].ls,p);
28     else updata(mid+1,r,t[u].rs,p);
29 }
30 int query(int l,int r,int u,int k){
31     if(l==r){
32         return l;
33     }
34     int mid=(l+r)/2,tmp=mid-l+1-t[t[u].ls].v;
35     if(tmp>=k)return query(l,mid,t[u].ls,k);
36     else return query(mid+1,r,t[u].rs,k-tmp);
37 }
38 ll del1(int p,ll x){
39     ll ret;
40     int nw=query(1,N,rts[n+1],p);
41     updata(1,N,rts[n+1],nw);
42     if(nw<=n)ret=(ll)nw*m;
43     else ret=v[n+1][nw-n-1];
44     if(x)v[n+1].push_back(x);
45     else v[n+1].push_back(ret);
46     return ret;
47 }
48 ll del2(int p,int x){
49     ll ret;
50     int nw=query(1,N,rts[p],x);
51     updata(1,N,rts[p],nw);
52     if(nw<m)ret=(ll)(p-1)*m+nw;
53     else ret=v[p][nw-m];
54     v[p].push_back(del1(p,ret));
55     return ret;
56 }
57 int main(){
58     scanf("%d%d%d",&n,&m,&q);
59     for(int i=1;i<=q;i++){
60         scanf("%d%d",&x,&y);
61         printf("%lld\n",y==m?del1(x,0):del2(x,y));
62     }
63     return 0;
64 }

总结:

感觉14~17年难度在递增……这个D2T2和D2T3都好神仙啊qwq

NOIP2018 加油!!!!!

posted @ 2018-11-09 14:26  DCDCBigBig  阅读(299)  评论(0编辑  收藏  举报