4.8省选模拟

信心赛\(?\)

考场上期望\(60+100+[0,30]\)

实际\(70+100+30=200\)

\(T1\)

考场上想到\(60\)分的区间\(dp\)就放弃梦想了。。。(不要学我)

正解是\(PAM\)上跑\(dp,\)当然了,在校内数据上,直接\(Manacher\)\(dp\)就可以了

本质上和区间\(dp\)一样

#define Eternal_Battle ZXK
#include<bits/stdc++.h>
#define int long long
#define MAXN 1000005
using namespace std;
char s[MAXN],Mid[MAXN];
int len[MAXN],tmp[MAXN],LEN[MAXN];
void Init()
{
	 int cnt=-1;
	 s[++cnt]='#';
	 for(int i=0;Mid[i];i++)
	 {
	 	 s[++cnt]='#';
	 	 s[++cnt]=Mid[i];
	 }
	 s[++cnt]='#';
}
void Manache()
{
	 int zj=0,Max=0;
	 for(int i=0;s[i];i++)
	 {
	 	if(i<=Max) len[i]=min(Max-i,len[2*zj-i]);
	 	while(s[i+len[i]]==s[i-len[i]]) len[i]++;
	 	if(i+len[i]>Max)
	 	{
	 	   Max=i+len[i];
		   zj=i;	
		}
	 }
}
int solve(int l,int r)
{
	 if(l>r)  return 0;
	 if(l==r) return 1;
	 int now=r-l+1,res=r-l+1;
     for(int i=l;i<=r;i++)
     {
     	 tmp[i]=min(LEN[i],min(r-i,i-l+1));
	 }
	 for(int i=l;i<=r;i++)
	 {
	 	 if(res<=now-2*tmp[i]) continue;
		 res=min(res,now-2*tmp[i]+(tmp[i]>0)+solve(i-tmp[i]+1,i)); 
	 }
	 return res;
}
void sol()
{
//	 memset(len,0,sizeof(len));
     scanf("%s",Mid);
     Init();
     Manache();
     int cnt=0;
     for(int i=3;s[i];i+=2)
     {
     	LEN[++cnt]=(len[i]-1)>>1;
//     	cout<<LEN[cnt]<<" ";
	 }
//	 cout<<"\n";
	 printf("%lld\n",solve(1,strlen(Mid)));
}
int T;
signed main()
{
	freopen("dna.in","r",stdin);
	freopen("dna.out","w",stdout);
    scanf("%lld",&T);
    while(T--) sol();
}

\(T2\)

考场上不会正解,观察大样例发现,这种造数据方式造的数据应该不强...

\(rand()\)一个前面点作为父亲的期望树高为\(log(n),\)那么就不必要想正解了,直接暴力修改链就好了...

大样例\(1.5s\)没事,卡常卡到了\(0.5s\)(真就大常数选手),然后出题人诚不欺我,就过了

#include<bits/stdc++.h>
#define rs ((now<<1)|1)
#define ll long long
#define MAXN 200005
#define ls (now<<1)
using namespace std;
template <typename T>
inline void read (T &a) {
	T x = 0, f = 1;
	char ch = getchar ();
	while (! isdigit (ch)) {
		(ch == '-') and (f = 0);
		ch = getchar ();
	}
	while (isdigit (ch)) {
		x = (x << 1) + (x << 3) + (ch xor '0');
		ch = getchar ();
	}
	a = f ? x : -x;
}
struct Tree
{
	   ll sum,add;
}tr[MAXN<<2];
int head[MAXN],nxt[MAXN],val[MAXN],to[MAXN],up[MAXN],Tim,tot,n,m;
int top[MAXN],dep[MAXN],siz[MAXN],son[MAXN],id[MAXN],bc[MAXN],f[MAXN];
bool vis[MAXN];
ll dis[MAXN],del[MAXN];
inline void add(int u,int v,int w)
{
	 tot++;
	 to[tot]=v;
	 val[tot]=w;
	 nxt[tot]=head[u];
	 head[u]=tot;
}
inline void dfs_pre(int now,int fa)
{ 
     int maxn=-1;
     dep[now]=dep[fa]+1;
	 siz[now]=1;
     f[now]=fa;
     for(int i=head[now];i;i=nxt[i])
     {
     	 int y=to[i];
     	 if(y==fa) continue;
     	 dis[y]=dis[now]+val[i];
     	 dfs_pre(y,now);
     	 siz[now]+=siz[y];
     	 if(siz[y]>maxn)
     	 {
     	 	maxn=siz[y];
     	 	son[now]=y;
     	 }
     }
}
inline void dfs_top(int now,int topn)
{
	 top[now]=topn;
	 id[now]=++Tim;
	 bc[Tim]=now;
	 if(!son[now]) return ;
	 dfs_top(son[now],topn);
	 for(int i=head[now];i;i=nxt[i])
	 {
	 	 int y=to[i];
	 	 if(top[y]) continue;
	 	 dfs_top(y,y);
	 }
}
inline void pd(int now,int L,int R)
{
	 if(tr[now].add)
	 {
	 	ll Add=tr[now].add;
        tr[ls].add+=Add;
        int mid=(L+R)>>1;
        tr[ls].sum+=(ll)(mid-L+1)*Add;
        tr[rs].add+=Add;
        tr[rs].sum+=(ll)(R-(mid+1)+1)*Add;
        tr[now].add=0;
 	 }
}
inline void change(int now,int L,int R,int l,int r,int k)
{
	 if(L>=l&&R<=r)
	 {
	 	tr[now].sum+=(ll)(R-L+1)*k;
	 	tr[now].add+=k;
	 	return ;
	 }
	 pd(now,L,R);
	 int mid=(L+R)>>1;
	 if(l<=mid) change(ls,L,mid,l,r,k);
	 if(r>mid)  change(rs,mid+1,R,l,r,k);
}
inline void change_lca(int x)
{
	 int lca=x,lst=0;
//     cout<<"OK";
 	 while(lca)
	 {
//	 	   cout<<"lca: "<<lca<<"\n";
	 	   for(int i=head[lca];i;i=nxt[i])
	 	   {
	 	   	   int y=to[i];
	 	   	   if(y==lst) continue;
	 	   	   change(1,1,n,id[y],id[y]+siz[y]-1,2*dis[lca]);
		   }
		   del[lca]+=2*dis[lca];
           lst=lca;
		   lca=f[lca];
	 }
}
inline ll query(int now,int L,int R,int poz)
{
	if(L==poz&&R==poz)
	{
	   return tr[now].sum;
	}
	pd(now,L,R);
	int mid=(L+R)>>1;
	if(poz<=mid) return query(ls,L,mid,poz);
	else return query(rs,mid+1,R,poz);
}
signed main()
{
	freopen("color.in","r",stdin);
	freopen("color.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=2;i<=n;i++)
	{
	    read(up[i]);	
//		scanf("%lld",&up[i]);
		up[i]++;
	}
	for(int i=2,w;i<=n;i++)
	{
//		scanf("%lld",&w);
		read(w);	
		add(up[i],i,w);
	}
//		printf("%.3f",(double)clock()/CLOCKS_PER_SEC);
	dfs_pre(1,0);
	dfs_top(1,1);
//	build(1,1,n);
	int Num=0;
	ll Sdp=0;
	for(int i=1,x,opt;i<=m;i++)
	{
//		scanf("%lld%lld",&opt,&x);
		read(opt);
		read(x);
		x++;
		if(opt==1)
		{
		   if(vis[x]) continue;
		   vis[x]=true;
		   Num++;
		   Sdp+=dis[x];
           change_lca(x);
		}
		else
		{
			ll Ans=(ll)Num*dis[x]+Sdp-query(1,1,n,id[x])-del[x];
			printf("%lld\n",Ans);
		}
	}
//	printf("%.3f",(double)clock()/CLOCKS_PER_SEC);
}

正解的话,也比较简单,直接把暴力改链的过程改成打标记就好了,不就\(O(nlog^2n)\)\(O(nlog^3n)\)的差距吗,\(/xyx\)

\(T3\)

状压\(dp\)

考场上乱搞一波,拿到\(30...\)(乱搞\(yyds\))

\(dp[x][y][S]\)表示目前在\((x,y)\)节点,已经把\(S\)包围起来的最小移动步数

最后答案就是\(val[S]-dp[sx][sy][S]\)

怎么判断一个点有没有在里面,直接判断向上的线穿过几次即可

有环的\(dp(guass?)\)

当然是最短路跑\(dp\)就好了

#include<bits/stdc++.h>
#define INF 2147483647
#define MAXN 30
using namespace std;
int dp[MAXN][MAXN][1<<10],gx[MAXN],gy[MAXN],val[MAXN];
int n,m,t,sx,sy,g[MAXN][MAXN],sum[1<<10];
int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};
struct nade
{
	int x,y,sta;
};
bool in(int x,int y,int xx,int yy,int i)
{
	if(xx==gx[i]&&yy<gy[i])if(x<xx)return 1;
	if(x==gx[i]&&y<gy[i])if(x>xx)return 1;
	return 0;
}
char s[MAXN][MAXN];
queue<nade>que;
int bfs()
{
	que.push(nade{sx,sy,0});
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			for(int sta=0;sta<(1<<t);sta++)
			{
				dp[i][j][sta]=-1;
			}
		}
	}
	dp[sx][sy][0]=0;
	while(!que.empty())
	{
		nade now=que.front();
		que.pop();
		int x=now.x,y=now.y,sta=now.sta;
		if(x==sx&&y==sy)ans=max(ans,sum[sta]-dp[x][y][sta]);
		for(int i=0;i<4;i++)
		{
			int xx=x+dx[i],yy=y+dy[i];
			if(xx<1||xx>n||yy<1||yy>m||(s[xx][yy]!='.'&&s[xx][yy]!='S'))continue;
			int chichi=sta;
			for(int j=1;j<=t;j++)
			{
				if(in(x,y,xx,yy,j))chichi^=1<<(j-1);
			}
			if(dp[xx][yy][chichi]==-1)
			{
				dp[xx][yy][chichi]=dp[now.x][now.y][sta]+1;
				que.push(nade{xx,yy,chichi});
			}
		}
	}
	return ans;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			char ch=s[i][j];
			if(ch=='S')
			{
				sx=i;
				sy=j;
			}
			else if(ch!='#'&&ch!='.'&&ch!='B')
			{
				gx[ch-48]=i;
				gy[ch-48]=j;
				t++;
			}
		}
	}
	for(int i=1;i<=t;i++) scanf("%d",&val[i]);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			char ch=s[i][j];
			if(ch=='B')
			{
				gx[++t]=i;
				gy[t]=j;
				val[t]=-INF;
			}
		}
	}
	for(int sta=1;sta<(1<<t);sta++)
	{
		for(int i=1;i<=t;i++)
		{
			if(sta&(1<<i-1))sum[sta]+=val[i];
		}
	}
	printf("%d\n",bfs());
}
posted @ 2022-04-08 16:05  Authentic_k  阅读(17)  评论(0编辑  收藏  举报