Loading

noip模拟19

A. u

一个更加巧妙的前缀和优化.
我们可以不仅仅对于横/纵开启前缀和优化,对于倾斜的线条也可以选择前缀和差分解决..
fengwuVaruxn画了图,可以根据\(ta\)们的来理解..

A_code
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define re register ll 
#define lf double
#define mp make_pair
const ll N=1050; 
inline void read(ll &ss)
{
	ss=0; bool cit=0; char ch;
	while(!isdigit(ch=getchar())) if(ch=='-') cit=1;
	while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
	if(cit) ss=-ss;
}
ll n,m;
ll r,c,l,s;
ll f1[N][N],f2[N][N];
ll f[N][N];
signed main()
{
	read(n); read(m);
	ll tmp1,tmp2;
	for(re i=1;i<=m;i++)
	{
		read(r); read(c); read(l); read(s);
		f1[r][c]+=s; f2[r][c+1]-=s;
		tmp1=min(n+1,r+l); tmp2=min(n+1,c+l);
		f1[tmp1][c]-=s; f2[tmp1][tmp2+1]+=s;
	}
	ll ans=0;
	for(re i=1;i<=n;i++)
	{
		for(re j=1;j<=n;j++)
		{
			f1[i][j]+=f1[i-1][j];
			f2[i][j]+=f2[i-1][j-1];
			f[i][j]=f1[i][j]+f2[i][j]+f[i][j-1];
			ans=ans xor f[i][j];
		}
	}
	printf("%lld",ans);
	return 0;
}

B. v

\(Hash\)+状压+记忆化搜索.
直接搜就行了,枚举每次选了哪个球,转移概率即可.

B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define ll int
	#define re register ll 
	#define lf double
	#define mp make_pair
	#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
	#define fill(x,y) memset(x,y,sizeof x);
	#define copy(x,y) memset(y,x,sizeof x);
	inline void read(ll &ss)
	{
		ss=0; bool cit=0; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=1;
		while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
		if(cit) ss=-ss;
	}
	inline void write(ll ss)
	{
		static int stas[35]; int topps=0;
  		if(ss<0) putchar('-'),ss=-ss;
  		do{stas[++topps]=ss%10,ss/=10;}while(ss);
  		while(topps) putchar(stas[topps--]+48); puts("");
	}
} using namespace BSS;
namespace HashTable
{
	const ll mod=1e6+3;
	struct Hash
	{
		ll head[mod*2+50],id,len;
		struct Node_Hash{ ll nxt,sta,len; lf val; } ed[mod*6];
		lf &operator [](ll sta)
		{
			ll now=1ll*sta*len%mod;
			for(re i=head[now];i;i=ed[i].nxt)
				if(ed[i].sta==sta and ed[i].len==len) return ed[i].val;
			ed[++id]=(Node_Hash){head[now],sta,len,-1.0};
			head[now]=id; return ed[id].val;
		}
	}H;
} using namespace HashTable;
const ll N=2e5+50;
ll n,m,ts,org;
ll del(ll now,ll i)
{
	ll temp1=now>>i; temp1=temp1<<(i-1);
	ll temp2=(1<<(i-1))-1; temp2=temp2&now;
	return temp1 | temp2;
}
lf dfs(ll now,ll cnt)
{
	if(cnt<=n-m) return 0;
	H.len=cnt;
	if(H[now]>-0.5) return H[now];
	lf sum=0.0;
	for(re i=1;i<=(cnt>>1);i++)
	{
		re tmp1=i,tmp2=cnt-i+1;
		//cout<<now<<" "<<del(now,tmp1)<<" "<<del(now,tmp2)<<" skr\n";
		lf temp1=dfs(del(now,tmp1),cnt-1)+((now>>tmp1-1)&1);
		lf temp2=dfs(del(now,tmp2),cnt-1)+((now>>tmp2-1)&1);
		H.len=cnt;		
		sum+=(max(temp1,temp2)*2);
	}
	if(cnt&1)
	{
		//cout<<now<<" "<<del(now,cnt/2+1)<<" der\n";
		H.len=cnt;
		sum+=(dfs(del(now,(cnt>>1)+1),cnt-1)+((now>>(cnt>>1))&1));
	}
	sum/=cnt;
	H.len=cnt;
	return (H[now]=sum);
}
signed main()
{
	read(n); read(m); char ch; lf sum=0;
	for(ll i=1;i<=n;i++)
	{
		cin>>ch; org<<=1;
		if(ch=='W') { org|=1; sum+=1; }
	}
	org|=(1<<n);
	printf("%0.8lf",dfs(org,n));
	return 0;
}

C. w

有一个我发现不了的性质:
对于任意一个即将翻转的集合\(S\),那么我们翻转的最少路径条数就是这个这个集合中有要求的边的度数为奇数的点的个数的一半.

证明:(归纳法可证)
(以下的度数均指这个点相连的有要求的边的个数)
由于我们需要让所有的奇数均作为某条路径的顶点,每次可以让度数为奇数的点的个数减少两个..
而我们之所以在只满足奇数点的过程中便可以满足偶数点,是因为每个偶数点都可以被看成是路径的一部分.

于是我们可以开始树规了.
\(dp_{i,0/1}\)表示这个点和父亲的边是否和父亲相连,于是乱搞即可.

C_code
#include<bits/stdc++.h>
using namespace std;
#define ll int
#define re register ll 
#define lf double
#define mp make_pair
const ll N=1e5+50;
inline void read(ll &ss)
{
	ss=0; bool cit=0; char ch;
	while(!isdigit(ch=getchar())) if(ch=='-') cit=1;
	while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
	if(cit) ss=-ss;
}
ll n,ts;
ll head[N];
pair<ll,ll> dp[N][2];
struct I { ll u,v,w,nxt; } e[N*2];
inline void add(ll u,ll v,ll w)
{
	e[++ts].u=u;
	e[ts].v=v;
	e[ts].w=w;
	e[ts].nxt=head[u];
	head[u]=ts;
}
pair<ll,ll> pls(pair<ll,ll> i,pair<ll,ll> j) { return mp(i.first+j.first,i.second+j.second); }
pair<ll,ll> getmin(pair<ll,ll> i,pair<ll,ll> j) { return i.first==j.first ? (i.second<j.second ? i : j) : (i.first<j.first ? i : j); }
void dfs(ll now,ll dad,ll w)
{
	pair<ll,ll> w1,w2,temp1,temp2;
	w1=mp(1e9,1e9); w2=mp(0,0);
	for(re i=head[now];i;i=e[i].nxt)
	{
		if(e[i].v==dad) continue;
		dfs(e[i].v,now,e[i].w);
		temp1=getmin(pls(dp[e[i].v][0],w1),pls(dp[e[i].v][1],w2));
		temp2=getmin(pls(dp[e[i].v][0],w2),pls(dp[e[i].v][1],w1));
		w1=temp1,w2=temp2;
	}
	if(w==1) dp[now][0]=mp(1e9,1e9);
	else dp[now][0]=getmin(w2,mp(w1.first+1,w1.second));
	if(w==0) dp[now][1]=mp(1e9,1e9); 
	else dp[now][1]=getmin(mp(w1.first,w1.second+1),mp(w2.first+1,w2.second+1));
	return ;
}
signed main()
{
	ll u,v,c,d;
	read(n);
	for(re i=1;i<=n-1;i++)
	{
		read(u); read(v); read(c); read(d);
		if(d&2) add(u,v,d),add(v,u,d);
		else add(u,v,(c^d)),add(v,u,(c^d));
	}
	dfs(1,0,2);
	printf("%d %d",dp[1][0].first>>1,dp[1][0].second);
	return 0;
}
posted @ 2021-08-05 19:54  AaMuXiiiiii  阅读(32)  评论(0编辑  收藏  举报