2019年8月6日(基本功练习3)
作者:互联网
看到\(DP\)就死了!!
prob1:中位数图
傻逼题,,,
因为是\(1\)到\(n\)的排列,所以我们可以准确的找到\(b\)的位置,设该位置下标为\(i\),从\(a_{i-1}\)的到\(a_1\)遍历一遍,\(a_j<b\)的\(smaller_j=smaller_{j+1}+1\),\(bigger_j\)继承\(bigger_{j+1}\),不变,若\(a_j>b\)则反之。同理,从\(i+1\)到\(n\)同样如此操作,这样就好出答案了……
明显,包含\(b\)的区间要不就以\(i\)为左界或右界,要不就将\(i\)包含在中间。若是前者,统计\(bigger_j=smaller_j\)的数量,对于后者,设左界为\(j\),右界为\(k\),则显然满足\(bigger_j+bigger_k=smaller_j+smaller_k\),移项得到\(bigger_j-smaller_j=smaller_k-bigger_k\),开个桶\(cnt\)统计一下就好了。
代码:
#include<iostream>
#include<cstdio>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define fdr(i,a,b) for(int i=a;i>=b;--i)
#define int long long
#define jinitaimei signed
inline int read()
{
int x=0;
char ch=getchar();
for(;!isalnum(ch);ch=getchar());
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x;
}
const int xx=1e5+10;
int a[xx],ans_place;
int bigger[xx],smaller[xx],cnt[xx<<1];
jinitaimei main()
{
int n=in,b=in,ans=0;
fur(i,1,n)
{
a[i]=in;
if(a[i]!=b) continue;
ans_place=i;
}
fdr(i,ans_place-1,1)
{
if(a[i]>b) smaller[i]=smaller[i+1],bigger[i]=bigger[i+1]+1;
if(a[i]<b) smaller[i]=smaller[i+1]+1,bigger[i]=bigger[i+1];
}
fur(i,ans_place+1,n)
{
if(a[i]>b) smaller[i]=smaller[i-1],bigger[i]=bigger[i-1]+1;
if(a[i]<b) smaller[i]=smaller[i-1]+1,bigger[i]=bigger[i-1];
}
fur(i,1,n) if(bigger[i]==smaller[i]) ++ans;
fur(i,ans_place+1,n) ++cnt[xx+smaller[i]-bigger[i]];
fur(i,1,ans_place-1) ans+=cnt[xx+bigger[i]-smaller[i]];
printf("%lld\n",ans);
return 0;
}
prob2:树
其实这题才是最水的,可惜我调倍增调了半天……
但这题暴力能过。表示不会证明复杂度,是数据太水了吗QWQ……
很明显点权都是正整数,链又得是连续的,所以当当前链的\(sum>s\)时,跳最深一个可以使\(sum_i-sum_{fa}<=s\)的进行删减,再统计答案。
思路很简单,暴力更简单(时间复杂度\(O(n^2)\),怀疑跑不满):
#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define fdr(i,a,b) for(int i=a;i>=b;--i)
#define int long long
#define jinitaimei signed
inline int read()
{
int x=0;
char ch=getchar();
for(;!isalnum(ch);ch=getchar());
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x;
}
const int xx=1e5+10;
bool root[xx];
vector<int>e[xx];
struct point{int fa,sum,w,dep;}dot[xx];
int k,n,rt,ans=0;
inline void dfs(int g)
{
if(dot[g].sum==k) ++ans;
if(dot[g].sum>k)
{
int jump=g;
while(dot[g].sum-dot[jump].sum<k) jump=dot[jump].fa;
if(dot[g].sum-dot[jump].sum==k) ++ans;
}
fur(i,0,(int)e[g].size()-1)
{
dot[e[g][i]].fa=g;
dot[e[g][i]].dep=dot[g].dep+1;
dot[e[g][i]].sum=dot[g].sum+dot[e[g][i]].w;
dfs(e[g][i]);
}
}
jinitaimei main()
{
n=in;k=in;
fur(i,1,n) dot[i].w=in;
fur(i,1,n-1)
{
int x=in,y=in;
e[x].push_back(y);
dot[y].fa=x;
root[y]=true;
}
fur(i,1,n) if(!root[i]) rt=i;
dot[rt].sum=dot[rt].w;
dfs(rt);
printf("%lld\n",ans);
return 0;
}
倍增(调了半天),时间复杂度(\(O(nlogn)\),但好像没暴力快):
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define fdr(i,a,b) for(int i=a;i>=b;--i)
#define int long long
#define jinitaimei signed
inline int read()
{
int x=0;
char ch=getchar();
for(;!isalnum(ch);ch=getchar());
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x;
}
const int xx=1e5+10;
bool root[xx];
vector<int>e[xx];
struct point{int fa[18],sum,w,dep;}dot[xx];
int k,n,rt,ans=0;
inline void dfs(int g)
{
if(dot[g].sum==k) ++ans;
if(dot[g].sum>k)
{
int jump=g;
fdr(i,17,0) if(dot[g].sum-dot[dot[jump].fa[i]].sum<k&&dot[g].fa[i]) jump=dot[jump].fa[i];
if(dot[g].sum-dot[dot[jump].fa[0]].sum==k) ++ans;
}
fur(i,0,(int)e[g].size()-1)
{
dot[e[g][i]].fa[0]=g;
dot[e[g][i]].dep=dot[g].dep+1;
dot[e[g][i]].sum=dot[g].sum+dot[e[g][i]].w;
fur(j,1,17) dot[e[g][i]].fa[j]=dot[dot[e[g][i]].fa[j-1]].fa[j-1];
dfs(e[g][i]);
}
}
jinitaimei main()
{
n=in;k=in;
fur(i,1,n) dot[i].w=in;
fur(i,1,n-1)
{
int x=in,y=in;
e[x].push_back(y);
dot[y].fa[0]=x;
root[y]=true;
}
fur(i,1,n) if(!root[i]) rt=i;
dot[rt].sum=dot[rt].w;
dfs(rt);
printf("%lld\n",ans);
return 0;
}
prob5:松鼠的新家
额,树剖板子题?
其实可以\(Tarjan\)求\(lca\)再树上差分,可以\(O(n)\)
可好久没写\(Tarjan\)了……
先给差分代码吧(用的是树剖跳\(lca\)):
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;i++)
#define int long long
#define jinitaimei signed
inline int read()
{
int x=0,f=1;char ch=getchar();
for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x*f;
}
const int xx=3e5+10;
int cf[xx],a[xx];
struct point{int top,son,fa,dep,sz;bool vis;}dot[xx];
vector<int>e[xx];
inline void dfs1(int g)
{
dot[g].sz=1;
fur(i,0,(int)e[g].size()-1)
{
if(dot[e[g][i]].vis) continue;
dot[e[g][i]].vis=true;
dot[e[g][i]].fa=g;
dot[e[g][i]].dep=dot[g].dep+1;
dfs1(e[g][i]);
dot[g].sz+=dot[e[g][i]].sz;
if(dot[e[g][i]].sz>dot[dot[g].son].sz) dot[g].son=e[g][i];
}
}
inline void dfs2(int g,int gg)
{
dot[g].top=gg;
if(dot[g].son) dfs2(dot[g].son,gg);
fur(i,0,(int)e[g].size()-1) if(e[g][i]!=dot[g].fa&&e[g][i]!=dot[g].son) dfs2(e[g][i],e[g][i]);
}
inline void dfs3(int g)
{
fur(i,0,(int)e[g].size()-1)
{
if(e[g][i]==dot[g].fa) continue;
dfs3(e[g][i]);
cf[g]+=cf[e[g][i]];
}
}
inline int lca(int u,int v)
{
while(dot[u].top!=dot[v].top)
{
if(dot[dot[u].top].dep<dot[dot[v].top].dep) swap(u,v);
u=dot[dot[u].top].fa;
}
return dot[u].dep<dot[v].dep?u:v;
}
jinitaimei main()
{
int n=in;
fur(i,1,n) a[i]=in;
fur(i,1,n-1)
{
int x=in,y=in;
e[x].push_back(y);
e[y].push_back(x);
}
dot[1].vis=true;
dfs1(1);
dfs2(1,1);
fur(i,1,n-1)
{
int q=lca(a[i],a[i+1]);
--cf[q];
--cf[dot[q].fa];
++cf[a[i]];
++cf[a[i+1]];
}
dfs3(1);
fur(i,2,n) --cf[a[i]];
fur(i,1,n) printf("%lld\n",cf[i]);
return 0;
}
树剖套线段树:
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;i++)
#define int long long
#define jinitaimei signed
inline int read()
{
int x=0,f=1;char ch=getchar();
for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x*f;
}
const int xx=3e5+10;
int a[xx],cnt=0,rk[xx],ans[xx];
struct linetree{int sum,lazy,l,r;}lt[xx<<2];
struct point{int top,id,son,fa,dep,sz;bool vis;}dot[xx];
vector<int>e[xx];
inline void dfs1(int g)
{
dot[g].sz=1;
fur(i,0,(int)e[g].size()-1)
{
if(dot[e[g][i]].vis) continue;
dot[e[g][i]].vis=true;
dot[e[g][i]].fa=g;
dot[e[g][i]].dep=dot[g].dep+1;
dfs1(e[g][i]);
dot[g].sz+=dot[e[g][i]].sz;
if(dot[e[g][i]].sz>dot[dot[g].son].sz) dot[g].son=e[g][i];
}
}
inline void dfs2(int g,int gg)
{
dot[g].id=++cnt;
rk[cnt]=g;
dot[g].top=gg;
if(dot[g].son) dfs2(dot[g].son,gg);
fur(i,0,(int)e[g].size()-1) if(e[g][i]!=dot[g].fa&&e[g][i]!=dot[g].son) dfs2(e[g][i],e[g][i]);
}
inline void up(int k)
{
int q=k<<1;
lt[k].sum=lt[q].sum+lt[q+1].sum;
}
inline void down(int k)
{
if(!lt[k].lazy) return;
int q=k<<1;
lt[q].lazy+=lt[k].lazy;
lt[q+1].lazy+=lt[k].lazy;
lt[q].sum+=lt[k].lazy*(lt[q].r-lt[q].l+1);
lt[q+1].sum+=lt[k].lazy*(lt[q+1].r-lt[q+1].l+1);
lt[k].lazy=0;
}
inline void build(int k,int i,int j)
{
lt[k].l=i;lt[k].r=j;
if(i==j)
{
lt[k].lazy=lt[k].sum=0;
return;
}
int q=k<<1,mid=(i+j)>>1;
build(q,i,mid);
build(q+1,mid+1,j);
up(k);
}
inline void add(int k,int i,int j)
{
if(i<=lt[k].l&&j>=lt[k].r)
{
lt[k].sum+=(lt[k].r-lt[k].l+1);
++lt[k].lazy;
return;
}
int q=k<<1,mid=lt[q].r;
if(i<=mid) add(q,i,j);
if(j>mid) add(q+1,i,j);
}
inline void downtown(int k)
{
if(lt[k].l==lt[k].r)
{
ans[rk[lt[k].l]]=lt[k].sum;
return;
}
down(k);
int q=k<<1;
downtown(q);
downtown(q+1);
}
inline void change(int u,int v)
{
while(dot[u].top!=dot[v].top)
{
if(dot[dot[u].top].dep<dot[dot[v].top].dep) swap(u,v);
add(1,dot[dot[u].top].id,dot[u].id);
u=dot[dot[u].top].fa;
}
if(dot[u].id>dot[v].id) swap(u,v);
add(1,dot[u].id,dot[v].id);
}
jinitaimei main()
{
int n=in;
fur(i,1,n) a[i]=in;
fur(i,1,n-1)
{
int x=in,y=in;
e[x].push_back(y);
e[y].push_back(x);
}
dot[a[1]].vis=true;
dfs1(a[1]);
dfs2(a[1],a[1]);
build(1,1,n);
fur(i,1,n-1) change(a[i],a[i+1]);
downtown(1);
fur(i,2,n) --ans[a[i]];
fur(i,1,n) printf("%lld\n",ans[i]);
return 0;
}
prob4:座位安排
写了好久的题解
prob3:Bill的挑战
最后一题,调到绝望。
全场就\(wyl\)巨佬切了这题,\(orz\)啊!!!
好吧,表示没看出来这是状压\(DP\).
设\(f_{i,j}\)为扫描到第\(i\)位,\(j\)的二进制下为各串是否匹配的方案数。
额……
讲不下去了,,,
好吧,状压\(DP\)貌似是我死穴,还是看这位大佬的吧
贴代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;i++)
#define int long long
#define jinitaimei signed
char s[16][51];
int ch[16][51];
int f[51][1<<16];
int has[27][27*15];
const int mod=1e6+3;
inline int num(int k){int ans=0;for(;k;k>>=1) if(k&1) ++ans;return ans;}
jinitaimei main()
{
int t;
scanf("%lld",&t);
while(t--)
{
int n,len,m;
scanf("%lld%lld",&n,&m);
fur(i,1,n)
{
scanf("%s",s[i]);
len=strlen(s[i]);
fur(j,0,len-1) ch[i][j]=isalpha(s[i][j])?(s[i][j]-'a'+1):27;
}
memset(f,-1,sizeof(f));
memset(has,0,sizeof(has));
f[0][(1<<n)-1]=1;
fur(i,1,len)
{
fur(P,0,(1<<n)-1)
{
if(f[i-1][P]==-1) continue;
fur(k,1,26) has[k][0]=0;
fur(k,1,n)
{
if((P&1<<(k-1))==0) continue;
if(ch[k][i-1]<27) has[ch[k][i-1]][++has[ch[k][i-1]][0]]=k;
else fur(j,1,26) has[j][++has[j][0]]=k;
}
fur(k,1,26)
{
if(!has[k][0]) continue;
int sum=0;
fur(j,1,has[k][0]) sum+=(1<<(has[k][j]-1));
if(f[i][sum]==-1) f[i][sum]=0;
(f[i][sum]+=f[i-1][P])%=mod;
}
}
}
int ans=0;
fur(i,0,(1<<n)-1)
{
if(num(i)!=m) continue;
if(f[len][i]==-1) continue;
(ans+=f[len][i])%=mod;
}
printf("%lld\n",ans);
}
return 0;
}
标签:ch,fur,int,练习,2019,基本功,include,dot,define 来源: https://www.cnblogs.com/ALANALLEN21LOVE28/p/11313042.html