原文地址:http://blog.csdn.net/clove_unique
Day 1
T1 直接根据题目描述的模拟就可以了,水。
【代码】
- #include<iostream>
- #include<cstring>
- #include<cstdio>
- using namespace std;
- int n,m,i,j,num;
- int a[50][50];
- int main(){
- scanf("%d",&n);
- m=(n/2)+1;
- a[1][m]=1;
- num=1;
- i=1; j=m;
- while (num<n*n){
- if (i==1&&j!=n) {a[n][j+1]=++num; i=n; ++j;}
- else if (i!=1&&j==n) {a[i-1][1]=++num; --i; j=1;}
- else if (i==1&&j==n) {a[i+1][j]=++num; ++i;}
- else if (i!=1&&j!=n){
- if (!a[i-1][j+1]) {a[i-1][j+1]=++num; --i; ++j;}
- else {a[i+1][j]=++num; ++i;}
- }
- }
- for (int i=1;i<=n;++i){
- for (int j=1;j<n;++j)
- printf("%d ",a[i][j]);
- printf("%d\n",a[i][n]);
- }
- return 0;
- }
T2 读了一遍题就看出来是最小环。刚开始忽略了有好几个联通块,大数据跑不对。最后写了个并查集+dfs,AC。水。
【代码】
- #include<iostream>
- #include<cstring>
- #include<cstdio>
- #define inf 2100000000
- #define N 200005
- using namespace std;
- int n,ans,y;
- int f[N],next[N],h[N];
- bool b[N];
- inline int in(){
- int x=0; char ch=getchar();
- while (ch<'0'||ch>'9') ch=getchar();
- while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
- return x;
- }
- int find(int x){
- if (x==f[x]) return x;
- f[x]=find(f[x]);
- return f[x];
- }
- void merge(int x,int y){
- int f1=find(x);
- int f2=find(y);
- f[f1]=f2;
- }
- void dfs(int x,int dep){
- b[x]=true; h[x]=dep;
- if (!b[next[x]])
- dfs(next[x],dep+1);
- else{
- int k=h[x]-h[next[x]]+1;
- ans=min(ans,k);
- }
- }
- int main(){
- n=in(); ans=inf;
- for (int i=1;i<=n;++i)
- f[i]=i;
- for (int i=1;i<=n;++i){
- y=in();
- next[i]=y;
- if (find(i)!=find(y))
- merge(i,y);
- else{
- memset(b,0,sizeof(b));
- dfs(i,1);
- }
- }
- printf("%d",ans);
- return 0;
- }
T3 时限2s内存1G就知道这道题一定很神。刚开始看到了之后一点思路都没有,以为是dp但是发现状态太多压不下。而且还有多组数据一旦跑不对就挂了。30分打表。
后来听到TA大爷说就是个dfs,把每一种情况编上号之后搜索就可以了。
好像也有dfs+dp的做法,不过我觉得这个更好理解。
1、单顺子 2、双顺子 3、三顺子 4、三带一、三带二 5、四带二、四带两对
由于每张牌的数量最多有4张,所以能保证这一种牌只要有就一定能一次打出去,所以出牌总次数的上限就是手牌的种类数。而每一次dfs都有一个新的上限,就是当前步数+现有的手牌的种类数。dfs过程中要进行最优化剪枝。
2016.10.28update
这题比较好理解,不过忘得差不多干净了之后又重写了一遍。
觉得现在的码风比原来好很多,所以把代码换掉_(:з」∠)_
【代码】
- #include<iostream>
- #include<cstring>
- #include<cstdio>
- using namespace std;
- int T,n,x,y,ans;
- int a[20];
- void clear()
- {
- memset(a,0,sizeof(a));
- ans=0;
- }
- bool check()
- {
- for (int i=1;i<=15;++i)
- if (a[i]) return false;
- return true;
- }
- void dfs(int dep)
- {
- if (dep>ans) return;
- if (check())
- {
- ans=min(ans,dep);
- return;
- }
- int sum=0;
- for (int i=1;i<=13;++i)
- if (a[i]) sum++;
- if (a[14]+a[15]) sum++;
- ans=min(ans,dep+sum);
- // 1 单顺子 2 双顺子 3 三顺子 4 三带一、三带二 5 四带二、四带两对
- for (int kind=1;kind<=5;++kind)
- {
- if (kind==1)
- {
- for (int i=1;i<=8;++i)
- if (a[i])
- {
- bool flag=true;
- for (int j=i+1;j<=i+3;++j)
- if (!a[j]) {flag=false;break;}
- if (!flag) continue;
- for (int j=i+4;j<13&&a[j];++j)
- {
- for (int k=i;k<=j;++k) --a[k];
- dfs(dep+1);
- for (int k=i;k<=j;++k) ++a[k];
- }
- }
- }
- if (kind==2)
- {
- for (int i=1;i<=10;++i)
- if (a[i]>=2&&a[i+1]>=2)
- for (int j=i+2;j<13&&a[j]>=2;++j)
- {
- for (int k=i;k<=j;++k) a[k]-=2;
- dfs(dep+1);
- for (int k=i;k<=j;++k) a[k]+=2;
- }
- }
- if (kind==3)
- {
- for (int i=1;i<=11;++i)
- if (a[i]>=3)
- {
- if (a[i+1]<3) continue;
- for (int j=i;j<13&&a[j]>=3;++j)
- {
- for (int k=i;k<=j;++k) a[k]-=3;
- dfs(dep+1);
- for (int k=i;k<=j;++k) a[k]+=3;
- }
- }
- }
- if (kind==4)
- {
- for (int i=1;i<=13;++i)
- if (a[i]>=3)
- {
- a[i]-=3;
- for (int j=1;j<=15;++j)
- if (a[j])
- {
- --a[j];
- dfs(dep+1);
- ++a[j];
- }
- for (int j=1;j<=15;++j)
- if (a[j]>=2)
- {
- a[j]-=2;
- dfs(dep+1);
- a[j]+=2;
- }
- a[i]+=3;
- }
- }
- if (kind==5)
- {
- for (int i=1;i<=15;++i)
- if (a[i]>=4)
- {
- a[i]-=4;
- for (int j=1;j<=15;++j)
- if (a[j])
- {
- --a[j];
- for (int k=j;k<=15;++k)
- if (a[k])
- {
- --a[k];
- dfs(dep+1);
- ++a[k];
- }
- ++a[j];
- }
- a[i]+=4;
- }
- for (int i=1;i<=15;++i)
- if (a[i]>=4)
- {
- a[i]-=4;
- for (int j=1;j<=15;++j)
- if (a[j]>=2)
- {
- a[j]-=2;
- for (int k=j;k<=15;++k)
- if (a[k]>=2)
- {
- a[k]-=2;
- dfs(dep+1);
- a[k]+=2;
- }
- a[j]+=2;
- }
- a[i]+=4;
- }
- }
- }
- }
- int main()
- {
- scanf("%d%d",&T,&n);
- while (T--)
- {
- clear();
- for (int i=1;i<=n;++i)
- {
- scanf("%d%d",&x,&y);
- if (!x) a[y+13]++;
- if (x==1||x==2) a[x+11]++;
- if (x>=3) a[x-2]++;
- }
- for (int i=1;i<=13;++i)
- if (a[i]) ans++;
- if (a[14]+a[15]) ans++;
- dfs(0);
- printf("%d\n",ans);
- }
- }
【代码】
- #include<algorithm>
- #include<iostream>
- #include<cstring>
- #include<cstdio>
- #define N 50005
- using namespace std;
- int L,n,m,l,r,mid,num;
- int a[N];
- int ok(int x){
- int ans=0,k=0;
- for (int i=1;i<=n+1;++i)
- if (a[i]-a[k]<x)
- ans++;
- else k=i;
- return ans;
- }
- int main(){
- scanf("%d%d%d",&L,&n,&m);
- for (int i=1;i<=n;++i)
- scanf("%d",&a[i]);
- sort(a+1,a+n+1);
- a[0]=0; a[n+1]=L;
- l=0; r=L;
- while(l<=r){
- mid=(l+r)/2;
- num=ok(mid);
- if (num<=m) l=mid+1;
- else r=mid-1;
- }
- printf("%d",l-1);
- }
T2 一眼就能看出来是dp,但是dp学的不好,想了一会没大有思路,就只写了30分的部分分。dfs没跑出来就只得了10分。
动规的思路看了ShallWe的代码才勉强理解,要是让我自己想是绝对想不到的,因为我当时连前缀和优化是什么都不怎么清楚。
f[i][j][k][l]表示第一个串的前i个,第二个串的前j个,分成k段,还有一维是前缀和,也可理解为选还是不选。注意这里的第一维要加一个滚动数组。
【代码】
- #include<iostream>
- #include<cstring>
- #include<cstdio>
- #define N 1005
- #define M 205
- #define p 1000000007
- using namespace std;
- char s1[N],s2[M];
- int n,m,k;
- int f[2][M][M][2];
- inline void in(){
- char ch=getchar();
- while (ch<'a'||ch>'z') ch=getchar();
- s1[1]=ch;
- for (int i=2;i<=n;++i) s1[i]=getchar();
- ch=getchar();
- while (ch<'a'||ch>'z') ch=getchar();
- s2[1]=ch;
- for (int i=2;i<=m;++i) s2[i]=getchar();
- }
- int main(){
- scanf("%d%d%d",&n,&m,&k);
- in();
- f[0][0][0][0]=1;
- f[1][0][0][0]=1;
- for (int i=1;i<=n;++i)
- for (int j=1;j<=min(i,m);++j)
- for (int l=1;l<=k;++l){
- int now=i&1,last=(i-1)&1;
- if (s1[i]==s2[j]){
- f[now][j][l][1]=((f[last][j-1][l-1][0]+f[last][j-1][l-1][1])%p+f[last][j-1][l][1])%p;
- f[now][j][l][0]=(f[last][j][l][0]+f[last][j][l][1])%p;
- }
- else{
- f[now][j][l][0]=(f[last][j][l][0]+f[last][j][l][1])%p;
- f[now][j][l][1]=0;
- }
- }
- printf("%d",(f[n&1][m][k][0]+f[n&1][m][k][1])%p);
- }
2016.10.27update
注意上文的“勉强理解”,今天把当时写的代码翻出来看看然后一脸懵逼,推翻重写。
可能是最近这种类型的dp做的比较多,现在看这道题就比较简单了。
同样是把代码先贴出来,详细题解
戳这里
撒花撒花~~
- #include<iostream>
- #include<cstring>
- #include<cstdio>
- using namespace std;
- #define N 1005
- #define M 205
- #define Mod 1000000007
- int n,m,p;
- int f[2][N][M],s[2][N][M],g[N][M];
- char a[N],b[M];
- void init()
- {
- for (int i=1;i<=n;++i)
- for (int j=1;j<=m;++j)
- {
- g[i][j]=min(i,j);
- for (int k=1;k<=min(i,j);++k)
- if (a[i-k+1]!=b[j-k+1])
- {
- g[i][j]=k-1;
- break;
- }
- }
- }
- int main()
- {
- scanf("%d%d%d\n",&n,&m,&p);
- gets(a+1);gets(b+1);
- init();
- for (int i=1;i<=m;++i)
- for (int j=i;j<=n;++j)
- {
- f[1][j][i]=f[1][j-1][i];
- if (g[j][i]==i) f[1][j][i]++;
- s[1][j][i]=s[1][j-1][i-1]+f[1][j][i];
- }
- for (int i=2;i<=p;++i)
- {
- memset(f[i&1],0,sizeof(f[i&1]));
- memset(s[i&1],0,sizeof(s[i&1]));
- for (int j=1;j<=n;++j)
- for (int k=1;k<=m;++k)
- {
- f[i&1][j][k]=f[i&1][j-1][k];
- if (g[j][k])
- {
- int x=s[(i-1)&1][j-1][k-1];
- f[i&1][j][k]=(f[i&1][j][k]+s[(i-1)&1][j-1][k-1])%Mod;
- int J=max(j-g[j][k]-1,0),K=max(k-g[j][k]-1,0);
- int y=s[(i-1)&1][J][K];
- f[i&1][j][k]=((f[i&1][j][k]-s[(i-1)&1][J][K])%Mod+Mod)%Mod;
- }
- s[i&1][j][k]=(s[i&1][j-1][k-1]+f[i&1][j][k])%Mod;
- }
- }
- printf("%d\n",f[p&1][n][m]);
- }
T3 第一眼觉得是倍增,然后各种写,越写越觉得太繁琐,好像实现不了。最后只写了一个链,时间复杂度还算错了,所以只有5分。其实还是有很多部分分的,但是考试时没有时间写了。
考完试思考了一下感觉还是做不大出来,听学长说了二分,不是很懂,下面的来自Rivendell的博客:
http://www.cnblogs.com/Rivendell/p/4972055.html
总的来说,NOIP2015做的还是可以的,简单一点的题没有丢分,但是有一些思考复杂度高一点的题目没有做出来,下一步应该加强训练。
2016.10.18update 时至今日,懒惰的Po终于把自己过掉的T3贴出来。
详细题解
戳这里
撒花~~
- #include<iostream>
- #include<cstring>
- #include<cstdio>
- using namespace std;
- #define N 300005
- #define sz 19
- int n,m,x,y,z,Max,dfs_clock,ans;
- int tot,point[N],nxt[N*2],v[N*2],c[N*2];
- int h[N],dis[N],val[N],num[N],tmp[N],f[N][sz+5];
- struct hp{int x,y,lca,dis;}edge[N];
- void addedge(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 build(int x,int fa)
- {
- num[++dfs_clock]=x;
- for (int i=1;i<sz;++i)
- {
- if ((h[x]-(1<<i))<1) break;
- f[x][i]=f[f[x][i-1]][i-1];
- }
- for (int i=point[x];i;i=nxt[i])
- if (v[i]!=fa)
- {
- f[v[i]][0]=x;
- h[v[i]]=h[x]+1;dis[v[i]]=dis[x]+c[i];val[v[i]]=c[i];
- build(v[i],x);
- }
- }
- int lca(int x,int y)
- {
- if (h[x]<h[y]) swap(x,y);
- int k=h[x]-h[y];
- for (int i=0;i<sz;++i)
- if ((1<<i)&k) x=f[x][i];
- if (x==y) return x;
- for (int i=sz-1;i>=0;--i)
- if (f[x][i]!=f[y][i])
- x=f[x][i],y=f[y][i];
- return f[x][0];
- }
- bool check(int mid)
- {
- int cnt=0,limit=0;memset(tmp,0,sizeof(tmp));
- for (int i=1;i<=m;++i)
- if (edge[i].dis>mid)
- {
- ++tmp[edge[i].x];++tmp[edge[i].y];tmp[edge[i].lca]-=2;
- limit=max(limit,edge[i].dis-mid);
- cnt++;
- }
- if (!cnt) return true;
- for (int i=n;i>1;--i) tmp[f[num[i]][0]]+=tmp[num[i]];
- for (int i=2;i<=n;++i)
- if (val[i]>=limit&&tmp[i]==cnt) return true;
- return false;
- }
- int find()
- {
- int l=0,r=Max,mid,ans;
- while (l<=r)
- {
- mid=(l+r)>>1;
- if (check(mid)) ans=mid,r=mid-1;
- else l=mid+1;
- }
- return ans;
- }
- int main()
- {
- scanf("%d%d",&n,&m);
- for (int i=1;i<n;++i)
- {
- scanf("%d%d%d",&x,&y,&z);
- addedge(x,y,z);Max+=z;
- }
- build(1,0);
- for (int i=1;i<=m;++i)
- {
- scanf("%d%d",&edge[i].x,&edge[i].y);
- edge[i].lca=lca(edge[i].x,edge[i].y);
- edge[i].dis=dis[edge[i].x]+dis[edge[i].y]-dis[edge[i].lca]*2;
- }
- ans=find();
- printf("%d\n",ans);
- }