NOIP2015 解题报告

过了这么久才来发解题报告,蒟蒻实在惭愧 /w\

Day1 T1

【思路】

模拟

【代码】

 1 #include<iostream>
 2 #include<cstring>
 3 #include<queue>
 4 #include<cmath>
 5 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
 6 using namespace std;
 7
 8 const int maxn = 50;
 9
10 int G[maxn][maxn];
11 int n,m;
12
13 int main() {
14     cin>>n;
15     int r=1,c=n/2+1;
16     G[r][c]=1;
17     FOR(i,2,n*n) {
18         if((r==1)&&(c!=n)) {
19             r=n; c++;
20             G[r][c]=i;
21         }
22         else if(c==n&&r!=1) {
23             c=1; r--;
24             G[r][c]=i;
25         }
26         else if(r==1 && c==n) {
27             r++;
28             G[r][c]=i;
29         }
30         else if(r!=1 && c!=n) {
31             if(!G[r-1][c+1]) {
32                 r--; c++;
33                 G[r][c]=i;
34             }
35             else {
36                 r++;
37                 G[r][c]=i;
38             }
39         }
40     }
41     FOR(i,1,n) {
42         FOR(j,1,n) cout<<G[i][j]<<" ";
43         cout<<endl;
44     }
45     return 0;
46 }

magic

Day1 T2

【思路】

Dfs,如果遇到已经访问的点则构成环更新ans

【代码】

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<queue>
 5 #include<algorithm>
 6 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
 7 using namespace std;
 8
 9 const int maxn = 200000+10;
10 struct Edge{
11     int v,next;
12 }e[maxn*10];
13 int en=-1,front[maxn];
14
15 int d[maxn];
16 int n,ans=1e9;
17 int vis[maxn];
18
19 void AddEdge(int u,int v) {
20     en++; e[en].v=v; e[en].next=front[u]; front[u]=en;
21 }
22
23 void dfs(int u,int fa){
24     for(int i=front[u];i>=0;i=e[i].next) {
25         int v=e[i].v;
26         if(v!=fa)
27         {
28             if(vis[v]) {
29                 ans=min(ans,abs(d[v]-d[u])+1);
30             }
31             else {
32                 vis[v]=1;
33                 d[v]=d[u]+1;
34                 dfs(v,u);
35             }
36         }
37     }
38 }
39 int read() {
40     char c=getchar();
41     while(!isdigit(c)) c=getchar();
42     int x=0;
43     while(isdigit(c)) {
44         x=x*10+c-‘0‘;
45         c=getchar();
46     }
47     return x;
48 }
49
50 int main() {
51     memset(front,-1,sizeof(front));
52     n=read();
53     int j;
54     FOR(i,1,n) {
55         j=read();
56         AddEdge(i,j);
57         AddEdge(j,i);
58     }
59     FOR(i,1,n) if(!vis[i]) {
60         vis[i]=1;
61         dfs(i,-1);
62     }
63     printf("%d",ans);
64     return 0;
65 } 

message

Day1 T3

【思路】

搜索+剪枝

忽略花色,统计每种码数出现次数方便出牌。

每次都先出顺子,对于手中剩下的牌我们贪心地将剩下的组合牌需要打的次数计算出来,然后更新ans以剪枝。

双王算作对牌。顺排不包括2和双王。

【代码】

 1 #include<cstdio>
 2 #include<cstring>
 3 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
 4 using namespace std;
 5
 6 const int N = 25;
 7
 8 int a[N],c[N];
 9 int n,T,ans;
10
11 int Qans() {
12     memset(c,0,sizeof(c));
13     FOR(i,0,13) c[a[i]]++;
14     int tot=0;                                    //tot带牌
15     while(c[4]&&c[2]>1)  c[4]--,c[2]-=2,tot++;
16     while(c[4]&&c[1]>1) c[4]--,c[1]-=2,tot++;
17     while(c[4]&&c[2]) c[4]--,c[2]--,tot++;
18     while(c[3]&&c[2]) c[3]--,c[2]--,tot++;
19     while(c[3]&&c[1]) c[3]--,c[1]--,tot++;
20     return tot+c[1]+c[2]+c[3]+c[4];                //带牌+三张 对子 单张
21 }
22
23 void dfs(int now) {
24     if(now>=ans) return ;
25     int tmp=Qans();
26     if(now+tmp<ans)  ans=now+tmp;
27     FOR(i,2,13) {                                //三顺子
28         int j=i;
29         while(a[j]>=3) j++;
30         if(j-i>=2) {
31             FOR(j2,i+1,j-1) {
32                 FOR(k,i,j2) a[k]-=3;
33                 dfs(now+1);
34                 FOR(k,i,j2) a[k]+=3;
35             }
36         }
37     }
38     FOR(i,2,13) {                                //双顺子
39         int j=i;
40         while(a[j]>=2) j++;
41         if(j-i>=3) {
42             FOR(j2,i+2,j-1) {
43                 FOR(k,i,j2) a[k]-=2;
44                 dfs(now+1);
45                 FOR(k,i,j2) a[k]+=2;
46             }
47         }
48     }
49     FOR(i,2,13) {                                //单顺子
50         int j=i;
51         while(a[j]>=1) j++;
52         if(j-i>=5) {
53             FOR(j2,i+4,j-1) {
54                 FOR(k,i,j2) a[k]--;
55                 dfs(now+1);
56                 FOR(k,i,j2) a[k]++;
57             }
58         }
59     }
60 }
61
62 int main() {
63     //freopen("in.in","r",stdin);
64     //freopen("out.out","w",stdout);
65     scanf("%d%d",&T,&n);
66     while(T--) {
67         memset(a,0,sizeof(a));
68         int x,y;
69         FOR(i,1,n) {
70             scanf("%d%d",&x,&y);
71             if(x==1) x=13; else if(x) x--;
72             a[x]++;
73         }
74         ans=1e9;
75         dfs(0);
76         printf("%d\n",ans);
77     }
78     return 0;
79 }

landlords

Day2 T1

【思路】

二分法

【代码】

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<queue>
 5 #include<cmath>
 6 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
 7 using namespace std;
 8
 9 const int maxn = 50000+10;
10
11 int d[maxn];
12 int n,m,len;
13
14 bool can(int M) {
15     int last=0,cur=1;
16     FOR(i,1,m) {
17         while(cur<=n && d[cur]-last<M) cur++;
18         if(d[cur]-last<M || (cur>n)) return false;
19         last=d[cur];
20     }
21     return true;
22 }
23
24 int main() {
25     cin>>len>>n>>m;
26     m=n-m;
27     FOR(i,1,n)  cin>>d[i];
28     int L=0,R=len;
29     while(L<R){
30         int M=L+(R-L+1)/2;
31         if(can(M)) L=M;
32         else R=M-1;
33     }
34     cout<<L;
35     return 0;
36 }

stone

Day2 T2

【思路】

DP+优化

设f[k][i][j]为已经有k段,A串匹配到i,B匹配到j的方案数,则有转移式:

f[k][i][j]=sigma{f[k-1][l][j-1]},A[i]==B[j]&&A[i-1]!=B[j-1]

= sigma{f[k-1][l][j-1]}+f[k][i-1][j-1],A[i]==B[j]&&A[i-1]==B[j-1]

前缀和优化时间,滚动数组优化空间。

【代码】

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4
 5 const int N = 1e3+5;
 6 const int M = 200+5;
 7 const int MOD = 1e9+7;
 8
 9 int f[2][N][M],sum[2][N][M],n,m,K;
10 char s1[N],s2[M];
11
12 int main() {
13     scanf("%d%d%d",&n,&m,&K);
14     scanf("%s",s1+1),scanf("%s",s2+1);
15     f[0][0][0]=1;
16     for(int i=0;i<=n;i++) sum[0][i][0]=1;
17     int x=0;
18     for(int k=1;k<=K;k++) {
19         x^=1;
20         memset(sum[x],0,sizeof(sum[x]));
21         memset(f[x],0,sizeof(f[x]));
22         for(int i=1;i<=n;i++)
23             for(int j=1;j<=m;j++) {
24                 if(s1[i]==s2[j]) {
25                     f[x][i][j]=sum[x^1][i-1][j-1];
26                     if(s1[i-1]==s2[j-1]) f[x][i][j]=(f[x][i][j]+f[x][i-1][j-1])%MOD;
27                 }
28                 sum[x][i][j]=((sum[x][i][j]+sum[x][i-1][j])%MOD+f[x][i][j])%MOD;
29             }
30     }
31     int ans=0;
32     for(int i=1;i<=n;i++)
33         ans=(ans+f[x][i][m])%MOD;
34     printf("%d",ans);
35     return 0;
36 }

substring

Day2 T3

【思路】

       二分+LCA+差分

先求出所有查询的路长,时间为O(mlogn)。题目所求为修改后的最大查询路最小,考虑二分该最大路值ML。对于所有长度超过ML的路径求交,记录最大查询路为mx,只要我们求出这些路径的最大公共边(交)mxe,通过判断mx-mxe与ML就可调整区间。

如何求交? 差分。所谓差分就是将一个对区间的操作变为对区间端点的操作。将查分推广到树上。每个结点带个cnt,对于路径(u,v),cnt[u]++,cnt[v]++,cnt[lca(u,v)]-=2,在树上统计cnt[x]=sigma{cnt[son]},这样只要满足cnt[x]==1的边就在这条路上,满足cnt[x]==tot的边就在路径的交上。

总的时间为O(mlogn+(m+n)logL)

【代码】

  1 #include<cstdio>
  2 #include<vector>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
  7 using namespace std;
  8
  9 const int N = 5*1e5+10;
 10 struct Edge{ int v,w; };
 11
 12 int n,m;
 13 int u[N],v[N],w[N],lca[N],dist[N],val[N];
 14 vector<Edge> g[N];
 15
 16 void read(int& x) {
 17     char c=getchar(); int f=1; x=0;
 18     while(!isdigit(c)) {if(c==‘-‘)f=-1; c=getchar();}
 19     while(isdigit(c)) x=x*10+c-‘0‘,c=getchar();
 20     x*=f;
 21 }
 22
 23 int siz[N],fa[N],son[N],top[N],dep[N],dis[N];
 24 void dfs1(int u) {
 25     siz[u]=1; son[u]=0;
 26     for(int i=0;i<g[u].size();i++) {
 27         int v=g[u][i].v;
 28         if(v!=fa[u]) {
 29             fa[v]=u; dep[v]=dep[u]+1;
 30             dis[v]=dis[u]+g[u][i].w;
 31             dfs1(v);
 32             siz[u]+=siz[v];
 33             if(siz[v]>siz[son[u]]) son[u]=v;
 34         }
 35     }
 36 }
 37 void dfs2(int u,int tp) {
 38     top[u]=tp;
 39     if(son[u]) dfs2(son[u],tp);
 40     for(int i=0;i<g[u].size();i++) {
 41         int v=g[u][i].v;
 42         if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
 43     }
 44 }
 45 int LCA(int u,int v) {
 46     while(top[u]!=top[v]) {
 47         if(dep[top[u]]<dep[top[v]]) swap(u,v);
 48         u=fa[top[u]];
 49     }
 50     return dep[u]<dep[v]? u:v;
 51 }
 52
 53 int tot,mx,mxe,cnt[N];
 54 int find_mxe(int u) {
 55     for(int i=0;i<g[u].size();i++) {
 56         int v=g[u][i].v;
 57         if(v!=fa[u]) cnt[u]+=find_mxe(v);
 58     }
 59     if(cnt[u]==tot) mxe=max(mxe,val[u]);
 60     int tmp=cnt[u]; cnt[u]=0;
 61     return tmp;
 62 }
 63 bool can(int ML) {
 64     tot=0; mx=mxe=0;
 65     FOR(i,1,m) if(dist[i]>ML){
 66         tot++; mx=max(mx,dist[i]);
 67         cnt[u[i]]++,cnt[v[i]]++,cnt[lca[i]]-=2;
 68     }
 69     find_mxe(1);
 70     return mx-mxe<=ML;
 71 }
 72
 73 int main() {
 74     freopen("transport.in","r",stdin);
 75     freopen("transport.out","w",stdout);
 76     read(n),read(m);
 77     FOR(i,1,n-1) {
 78         read(u[i]),read(v[i]),read(w[i]);
 79         g[u[i]].push_back((Edge){v[i],w[i]});
 80         g[v[i]].push_back((Edge){u[i],w[i]});
 81     }
 82     dfs1(1),dfs2(1,1);
 83     FOR(i,1,n-1) {
 84         if(dep[u[i]]<dep[v[i]]) swap(u[i],v[i]);
 85         val[u[i]]=w[i];
 86     }
 87     int x,y,L=0,R=0,M;
 88     FOR(i,1,m) {
 89         read(x),read(y);
 90         dist[i]=dis[x]+dis[y]-2*dis[lca[i]=LCA(x,y)];
 91         R=max(R,dist[i]); u[i]=x,v[i]=y;
 92     }
 93     R++;
 94     while(L<R) {
 95         M=(L+R)>>1;
 96         if(can(M)) R=M; else L=M+1;
 97     }
 98     printf("%d",L);
 99     return 0;
100 }

transport

NOIP2015 所涉及到的知识有:模拟,二分法,搜索及优化,DP及优化,LCA

PS:Day1 T2 和 Day2 T3在部分OJ会栈溢出

题目/数据传送门

时间: 2024-07-30 13:38:13

NOIP2015 解题报告的相关文章

习题:codevs 1035 火车停留解题报告

本蒟蒻又来写解题报告了.这次的题目是codevs 1035 火车停留. 题目大意就是给m个火车的到达时间.停留时间和车载货物的价值,车站有n个车道,而火车停留一次车站就会从车载货物价值中获得1%的利润,让你来求一种安排方法,使得车站收益最大,并输出收益值. 蒟蒻的思路是这样的: 一眼看出:最大费用最大流(MCMF)显然cost:表示车站收益然后……以车站为点建立图求流?同一个车站可能经过好几辆火车……,貌似很麻烦……:那么以什么建图.连边,还有怎么连?貌似有点类似于方格取数2之中的拆点……:那么

解题报告 之 POJ3057 Evacuation

解题报告 之 POJ3057 Evacuation Description Fires can be disastrous, especially when a fire breaks out in a room that is completely filled with people. Rooms usually have a couple of exits and emergency exits, but with everyone rushing out at the same time

hdu 1541 Stars 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1541 题目意思:有 N 颗星星,每颗星星都有各自的等级.给出每颗星星的坐标(x, y),它的等级由所有比它低层(或者同层)的或者在它左手边的星星数决定.计算出每个等级(0 ~ n-1)的星星各有多少颗. 我只能说,题目换了一下就不会变通了,泪~~~~ 星星的分布是不是很像树状数组呢~~~没错,就是树状数组题来滴! 按照题目输入,当前星星与后面的星星没有关系.所以只要把 x 之前的横坐标加起来就可以了

【百度之星2014~初赛(第二轮)解题报告】Chess

声明 笔者最近意外的发现 笔者的个人网站http://tiankonguse.com/ 的很多文章被其它网站转载,但是转载时未声明文章来源或参考自 http://tiankonguse.com/ 网站,因此,笔者添加此条声明. 郑重声明:这篇记录<[百度之星2014~初赛(第二轮)解题报告]Chess>转载自 http://tiankonguse.com/ 的这条记录:http://tiankonguse.com/record/record.php?id=667 前言 最近要毕业了,有半年没做

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告 勘误1:第6题第4个 if最后一个条件粗心写错了,答案应为1580. 条件应为abs(a[3]-a[7])!=1,宝宝心理苦啊.!感谢zzh童鞋的提醒. 勘误2:第7题在推断连通的时候条件写错了,后两个if条件中是应该是<=12 落了一个等于号.正确答案应为116. 1.煤球数目 有一堆煤球.堆成三角棱锥形.详细: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第四层10个(排列成三角形). -. 假设一共

[noip2011]铺地毯(carpet)解题报告

最近在写noip2011的题,备战noip,先给自己加个油! 下面是noip2011的试题和自己的解题报告,希望对大家有帮助,题目1如下 1.铺地毯(carpet.cpp/c/pas) [问题描述]为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有n 张地毯,编号从1 到n.现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上.地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的

ACdream 1203 - KIDx&#39;s Triangle(解题报告)

KIDx's Triangle Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) Submit Statistic Next Problem Problem Description One day, KIDx solved a math problem for middle students in seconds! And than he created this problem. N

解题报告 之 CodeForces 91B Queue

解题报告 之 CodeForces 91B Queue Description There are n walruses standing in a queue in an airport. They are numbered starting from the queue's tail: the 1-st walrus stands at the end of the queue and the n-th walrus stands at the beginning of the queue.

解题报告 之 POJ1226 Substrings

解题报告 之 POJ1226 Substrings Description You are given a number of case-sensitive strings of alphabetic characters, find the largest string X, such that either X, or its inverse can be found as a substring of any of the given strings. Input The first li