NOI2015 题解
D1T1 程序自己主动分析
题目大意:给定
并查集傻逼题。NOIP小孩都会做
离散化一下,然后把相等的都用并查集并起来,推断每对不等关系是不是在同一并查集中即可了
代码没拷回来,懒得再写一遍了
D2T2 软件包管理器
题目大意:给定一棵有根树。每一个点有黑白两种颜色,初始都为白色,每次进行下面两种操作:
1.将某个点所在的子树染白
2.将某个点到根路径上的点染黑
求每次操作后有多少点的颜色发生了改变
树剖傻逼题。NOIP小孩都会做
维护一棵有根树,支持链查询,链改动,子树查询,子树改动
显然链剖即可了
代码也没拷回来。懒得再写一遍了
D3T3 寿司晚宴
题目大意:给定
DP傻逼题,我居然不会做
首先我们把一个数字看成这样一坨东西:
小于
大于
那么显然一类数最多仅仅有一个人能取 两个人都取同一类数的话就会出现不互质的情况
然后我们就能够DP辣!!
令
令
枚举每一类数,首先将
什么你问我为何要减掉
时间复杂度
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 550
using namespace std;
const int prime[]={2,3,5,7,11,13,17,19};
int n,p;
int f[1<<8][1<<8],g[2][1<<8][1<<8];
pair<int,int> stack[550];
int main()
{ int i,j,k;
cin>>n>>p;
for(i=1;i<=n;i++)
{
int temp=i;
for(j=0;j<8;j++)
if(temp%prime[j]==0)
{
stack[i].second|=1<<j;
while(temp%prime[j]==0)
temp/=prime[j];
}
stack[i].first=temp;
}
sort(stack+2,stack+n+1);
f[0][0]=1;
for(i=2;i<=n;i++)
{
if( i==2 || stack[i].first==1 || stack[i].first!=stack[i-1].first )
{
memcpy(g[0],f,sizeof f);
memcpy(g[1],f,sizeof f);
}
for(j=255;~j;j--)
for(k=255;~k;k--)
{
if( (stack[i].second&k)==0 )
(g[0][j|stack[i].second][k]+=g[0][j][k])%=p;
if( (stack[i].second&j)==0 )
(g[1][j][k|stack[i].second]+=g[1][j][k])%=p;
}
if( i==n || stack[i].first==1 || stack[i].first!=stack[i+1].first )
{
for(j=0;j<1<<8;j++)
for(k=0;k<1<<8;k++)
f[j][k]=((g[0][j][k]+g[1][j][k]-f[j][k])%p+p)%p;
}
}
int ans=0;
for(j=0;j<1<<8;j++)
for(k=0;k<1<<8;k++)
if( (j&k)==0 )
(ans+=f[j][k])%=p;
cout<<ans<<endl;
return 0;
}
D2T1 荷马史诗
题目大意:给定一篇文章中每一个字母的出现次数,要求为每一个字母设计一个
k-哈夫曼树就是一次合并k个,假设有零头的话就先把零头合并
最长的字母最短就是每次找高度最小的树合并
别问我怎么证明。我连合并果子都不会证…
代码:
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
struct abcd{
long long size;
int dpt;
abcd() {}
abcd(long long _,int __):
size(_),dpt(__) {}
friend bool operator < (const abcd &x,const abcd &y)
{
if(x.size!=y.size)
return x.size>y.size;
return x.dpt>y.dpt;
}
};
int n,k,ans2;
long long ans1;
priority_queue<abcd> heap;
void Merge(int cnt)
{
long long _size=0;
int _dpt=0;
while(cnt--)
{
abcd temp=heap.top();heap.pop();
_size+=temp.size;
_dpt=max(_dpt,temp.dpt);
}
ans1+=_size;
ans2=max(ans2,++_dpt);
heap.push(abcd(_size,_dpt));
}
int main()
{
int i;long long x;
cin>>n>>k;
for(i=1;i<=n;i++)
{
scanf("%lld",&x);
heap.push(abcd(x,0));
}
if( (n-1)%(k-1)+1!=1 && n!=1 )
Merge( min( (n-1)%(k-1)+1 , n ) );
while(heap.size()>1)
Merge( min( k , (int)heap.size() ) );
cout<<ans1<<'\n'<<ans2<<endl;
return 0;
}
D2T2 品酒大会
题目大意:给定一个长度为
神木韵律的超
求出后缀数组后从大到小枚举
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 300300
using namespace std;
int n;
char s[M];
long long ans1[M],ans2[M];
namespace Suffix_Array{
int sa[M],rank[M],height[M];
int X[M],Y[M],temp[M],tot;
void Get_Rank()
{
static int sum[M];
int i;
for(i=1;i<=n;i++)
sum[s[i]]++;
for(i=1;i<=200;i++)
sum[i]+=sum[i-1];
for(i=n;i;i--)
sa[sum[s[i]]--]=i;
for(i=1;i<=n;i++)
{
if( i==1 || s[sa[i-1]]!=s[sa[i]] )
++tot;
rank[sa[i]]=tot;
}
}
void Radix_Sort(int key[],int order[])
{
static int sum[M];
int i;
for(i=0;i<=n;i++)
sum[i]=0;
for(i=1;i<=n;i++)
sum[key[i]]++;
for(i=1;i<=n;i++)
sum[i]+=sum[i-1];
for(i=n;i;i--)
temp[sum[key[order[i]]]--]=order[i];
for(i=1;i<=n;i++)
order[i]=temp[i];
}
void Get_Height()
{
int i,j,k;
for(i=1;i<=n;i++)
{
if(rank[i]==1)
continue;
j=sa[rank[i]-1];
k=max(0,height[rank[i-1]]-1);
while(s[i+k]==s[j+k])
++k;
height[rank[i]]=k;
}
}
void Prefix_Doubling()
{
int i,j;
Get_Rank();
for(j=1;j<=n;j<<=1)
{
for(i=1;i<=n;i++)
{
X[i]=rank[i];
Y[i]=i+j>n?0:rank[i+j];
sa[i]=i;
}
Radix_Sort(Y,sa);
Radix_Sort(X,sa);
for(tot=0,i=1;i<=n;i++)
{
if( i==1 || X[sa[i]]!=X[sa[i-1]] || Y[sa[i]]!=Y[sa[i-1]] )
++tot;
rank[sa[i]]=tot;
}
}
Get_Height();
}
}
namespace Union_Find_Set{
int fa[M],rank[M],size[M],max_val[M],min_val[M];
int Find(int x)
{
if(!fa[x])
size[x]=1,fa[x]=x;
if(fa[x]==x)
return x;
return fa[x]=Find(fa[x]);
}
void Union(int x,int y)
{
x=Find(x);y=Find(y);
if(x==y) return ;
if(rank[x]>rank[y])
swap(x,y);
if(rank[x]==rank[y])
++rank[y];
fa[x]=y;size[y]+=size[x];
max_val[y]=max(max_val[x],max_val[y]);
min_val[y]=min(min_val[x],min_val[y]);
}
}
bool Compare(int x,int y)
{
using namespace Suffix_Array;
return height[x]>height[y];
}
int main()
{
using namespace Suffix_Array;
using namespace Union_Find_Set;
int i,x,y;
cin>>n;scanf("%s",s+1);
Prefix_Doubling();
for(i=1;i<=n;i++)
{
scanf("%d",&x);
max_val[Suffix_Array::rank[i]]=min_val[Suffix_Array::rank[i]]=x;
}
static int a[M];
for(i=2;i<=n;i++)
a[i-1]=i;
sort(a+1,a+n,Compare);
memset(ans2,0xef,sizeof ans2);
for(i=1;i<n;i++)
{
x=Find(a[i]-1),y=Find(a[i]);
ans1[height[a[i]]]+=(long long)size[x]*size[y];
ans2[height[a[i]]]=max(ans2[height[a[i]]],(long long)min_val[x]*min_val[y]);
ans2[height[a[i]]]=max(ans2[height[a[i]]],(long long)min_val[x]*max_val[y]);
ans2[height[a[i]]]=max(ans2[height[a[i]]],(long long)max_val[x]*min_val[y]);
ans2[height[a[i]]]=max(ans2[height[a[i]]],(long long)max_val[x]*max_val[y]);
Union(x,y);
}
for(i=n-1;~i;i--)
{
ans1[i]+=ans1[i+1];
ans2[i]=max(ans2[i],ans2[i+1]);
}
for(i=0;i<n;i++)
printf("%lld %lld\n",ans1[i],ans1[i]==0?0:ans2[i]);
return 0;
}
D2T3 小园丁与老司机
题目大意:给定平面上
1.最多能到达多少个点
2.输出随意一组方案
3.将全部方案中的左上、上、右上的路径连起来。求最小路径覆盖
DP,记录方案,建图跑最小流,这题仅仅有细节,仅仅有细节……
我的代码写了个费用流。被第7个点卡出翔过不了……
#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 50500
#define S (M-1)
#define T (M-2)
#define INF 0x3f3f3f3f
using namespace std;
struct Point{
int x,y,id;
friend istream& operator >> (istream &_,Point &p)
{
return scanf("%d%d",&p.x,&p.y),_;
}
friend bool operator < (const Point &p1,const Point &p2)
{
if( p1.y!=p2.y )
return p1.y < p2.y ;
return p1.x < p2.x ;
}
}points[M];
int n,ans1,ans1_ed,ans2;
int f[M],g[M],from[M],_from[M];
map<int,int> m1,m2,m3;
namespace Max_Cost_Max_Flow{
struct abcd{
int to,flow,cost,next;
}table[2002002];
int head[M],tot=1;
void Add(int x,int y,int f,int c)
{
table[++tot].to=y;
table[tot].flow=f;
table[tot].cost=c;
table[tot].next=head[x];
head[x]=tot;
}
void Link(int x,int y,int f,int c)
{
Add(x,y,f,c);
Add(y,x,0,-c);
}
bool Edmonds_Karp()
{
static int q[65540],flow[M],cost[M],from[M];
static unsigned short r,h;
static bool v[M];
int i;
memset(cost,0xef,sizeof cost);
flow[S]=INF;cost[S]=0;q[++r]=S;
while(r!=h)
{
int x=q[++h];v[x]=false;
for(i=head[x];i;i=table[i].next)
if(table[i].flow&&cost[table[i].to]<cost[x]+table[i].cost)
{
cost[table[i].to]=cost[x]+table[i].cost;
flow[table[i].to]=min(flow[x],table[i].flow);
from[table[i].to]=i;
if(!v[table[i].to])
v[table[i].to]=true,q[++r]=table[i].to;
}
}
if(cost[T]<=0) return false;
ans2+=flow[T];
for(i=from[T];i;i=from[table[i^1].to])
table[i].flow-=flow[T],table[i^1].flow+=flow[T];
return true;
}
}
int main()
{
using namespace Max_Cost_Max_Flow;
int i,j;
cin>>n;
for(i=1;i<=n;i++)
cin>>points[i],points[i].id=i;
sort(points+1,points+n+1);
static int stack[M],top;
memset(f,0xef,sizeof f);f[0]=0;
for(i=0;i<=n;i++)
{
if(m1.find(points[i].x)!=m1.end())
{
int temp=m1[points[i].x];
if(f[temp]+1>f[i]) f[i]=f[temp]+1,from[i]=temp;
}
m1[points[i].x]=i;
if(m2.find(points[i].x+points[i].y)!=m2.end())
{
int temp=m2[points[i].x+points[i].y];
if(f[temp]+1>f[i]) f[i]=f[temp]+1,from[i]=temp;
}
m2[points[i].x+points[i].y]=i;
if(m3.find(points[i].x-points[i].y)!=m3.end())
{
int temp=m3[points[i].x-points[i].y];
if(f[temp]+1>f[i]) f[i]=f[temp]+1,from[i]=temp;
}
m3[points[i].x-points[i].y]=i;
stack[++top]=i;
if( i==n || points[i+1].y!=points[i].y )
{
static int _f[M];
for(j=1;j<=top;j++)
{
_f[stack[j]]=f[stack[j]];
_from[stack[j]]=from[stack[j]];
}
int max_pos=-1;
for(j=2;j<=top;j++)
{
if( max_pos==-1 || _f[stack[j-1]]>_f[stack[max_pos]] )
max_pos=j-1;
if( _f[stack[max_pos]]+(j-1)>f[stack[j]] )
f[stack[j]]=_f[stack[max_pos]]+(j-1),from[stack[j]]=stack[max_pos];
}
max_pos=-1;
for(j=top-1;j;j--)
{
if( max_pos==-1 || _f[stack[j+1]]>_f[stack[max_pos]] )
max_pos=j+1;
if( _f[stack[max_pos]]+(top-j)>f[stack[j]] )
f[stack[j]]=_f[stack[max_pos]]+(top-j),from[stack[j]]=stack[max_pos];
}
for(j=1;j<=top;j++)
if(f[stack[j]]>ans1)
ans1=f[stack[j]],ans1_ed=stack[j];
top=0;
}
}
cout<<ans1<<endl;
bool flag=false;
while(ans1_ed)
{
stack[++top]=points[ans1_ed].id;
if(flag)
{
flag=false;
ans1_ed=_from[ans1_ed];
continue;
}
if(points[ans1_ed].y==points[from[ans1_ed]].y)
{
if(ans1_ed>from[ans1_ed])
{
for(i=ans1_ed-1;i!=from[ans1_ed];i--)
stack[++top]=points[i].id;
for(i--;points[i].y==points[ans1_ed].y;i--);
for(i++;i!=from[ans1_ed];i++)
stack[++top]=points[i].id;
}
else
{
for(i=ans1_ed+1;i!=from[ans1_ed];i++)
stack[++top]=points[i].id;
for(i++;points[i].y==points[ans1_ed].y;i++);
for(i--;i!=from[ans1_ed];i--)
stack[++top]=points[i].id;
}
flag=true;
}
ans1_ed=from[ans1_ed];
}
//cout<<top<<endl;
while(top)
printf("%d ",stack[top--]);
puts("");
m1.clear();
m2.clear();
m3.clear();
memcpy(g,f,sizeof g);
for(i=n;~i;i--)
{
f[i]=(i!=0);
if(m1.find(points[i].x)!=m1.end())
{
int temp=m1[points[i].x];
f[i]=max(f[temp]+(i!=0),f[i]);
//printf("%d\n",g[i]+f[temp]);
if(g[i]+f[temp]==ans1)
{
Link(temp,i,1,1);
Link(temp,i,INF,0);
}
}
m1[points[i].x]=i;
if(m2.find(points[i].x+points[i].y)!=m2.end())
{
int temp=m2[points[i].x+points[i].y];
f[i]=max(f[temp]+(i!=0),f[i]);
//printf("%d\n",g[i]+f[temp]);
if(g[i]+f[temp]==ans1)
{
Link(temp,i,1,1);
Link(temp,i,INF,0);
}
}
m2[points[i].x+points[i].y]=i;
if(m3.find(points[i].x-points[i].y)!=m3.end())
{
int temp=m3[points[i].x-points[i].y];
f[i]=max(f[temp]+(i!=0),f[i]);
//printf("%d\n",g[i]+f[temp]);
if(g[i]+f[temp]==ans1)
{
Link(temp,i,1,1);
Link(temp,i,INF,0);
}
}
m3[points[i].x-points[i].y]=i;
stack[++top]=i;
if( i==0 || points[i-1].y!=points[i].y )
{
static int _f[M];
for(j=1;j<=top;j++)
_f[stack[j]]=f[stack[j]];
int max_pos=-1;
for(j=2;j<=top;j++)
{
if( max_pos==-1 || _f[stack[j-1]]+(top-j+1)>_f[stack[max_pos]]+(top-max_pos) )
max_pos=j-1;
if( _f[stack[max_pos]]+(top-max_pos)>f[stack[j]] )
f[stack[j]]=_f[stack[max_pos]]+(top-max_pos);
}
max_pos=-1;
for(j=top-1;j;j--)
{
if( max_pos==-1 || _f[stack[j+1]]+(j)>_f[stack[max_pos]]+(max_pos-1) )
max_pos=j+1;
if( _f[stack[max_pos]]+(max_pos-1)>f[stack[j]] )
f[stack[j]]=_f[stack[max_pos]]+(max_pos-1);
}
top=0;
}
}
m1.clear();
m2.clear();
m3.clear();
/*
for(i=0;i<=n;i++)
printf("%d\n",f[i]+g[i]);
for(i=0;i<=n;i++)
{
if(m1.find(points[i].x)!=m1.end())
{
int temp=m1[points[i].x];
if(g[temp]+f[i]==ans1)
{
Link(temp,i,1,1);
Link(temp,i,INF,0);
}
}
m1[points[i].x]=i;
if(m2.find(points[i].x+points[i].y)!=m2.end())
{
int temp=m2[points[i].x+points[i].y];
if(g[temp]+f[i]==ans1)
{
Link(temp,i,1,1);
Link(temp,i,INF,0);
}
}
m2[points[i].x+points[i].y]=i;
if(m3.find(points[i].x-points[i].y)!=m3.end())
{
int temp=m3[points[i].x-points[i].y];
if(g[temp]+f[i]==ans1)
{
Link(temp,i,1,1);
Link(temp,i,INF,0);
}
}
m3[points[i].x-points[i].y]=i;
}
*/
for(i=0;i<=n;i++)
{
Link(S,i,INF,0);
Link(i,T,INF,0);
}
while( Edmonds_Karp() );
cout<<ans2<<endl;
return 0;
}