Loading

noip模拟20

A. 玩具

这个题目告诉我们,有些\(dp\)的设计并不是很切合题目,但是却可以进行转移并得到正确的答案.
image

A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define ll long long 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) memcpy(x,y,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;

const ll N=210;

ll m,n,mod;
ll inv[N];
ll dp[N][N],f[N][N],g[N][N];
inline ll ksm(ll a,ll b,ll c)
{
	ll temp=1; a=a%c;
	while(b)
	{
		if(b&1) temp=(temp*a)%c;
		a=(a*a)%c; b>>=1;
	}
	return temp%c;
}
signed main()
{
	read(n); read(mod);
	for(re i=1;i<=n;i++)
		inv[i]=ksm(i,mod-2,mod);
	dp[1][1]=1;
	for(re i=2;i<=n;i++)
	{
		for(re j=1;j<=i;j++)
		{
			dp[i][j]=(dp[i-1][j-1]*(j-1)%mod*inv[i]%mod+dp[i-1][j]*(i-j)%mod*inv[i]%mod)%mod;
		}
	}
	g[0][0]=1;
	for(re i=0;i<=n;i++)
	{
		g[0][i]=1;
		for(re j=0;j<=n;j++)
		{
			if(j) f[i][j]=g[i-1][j-1];
			if(i<=j){ g[i][j]=1; continue; }
			for(re k=0;k<=i;k++)
			{
				g[i][j]=(g[i][j]+f[k][j]*g[i-k][j]%mod*dp[i][k]%mod)%mod;
			}
		}
	}
	ll ans=0;
	for(ll i=2;i<=n;i++)
	{
		ans=(ans+(f[n][i]-f[n][i-1]+mod*1000000)%mod*i%mod)%mod;
	//	cout<<(f[n][i]-f[n][i-1]+mod*100)*i%mod<<endl;
	}
	printf("%lld",ans-1);
} 

B. y

第一次接触\(meet\ in\ the\ middle\)优化指数.
学会之后这道题看起来便不是那么遥不可及了..
枚举断点然后转移就行了.

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) memcpy(x,y,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;

const ll N=100;
ll n,m,d,ts,cnt;
ll head[N];
ll vis[(1<<22)+50];
ll f[N][N][(1<<12)+50];
struct I { ll u,v,w,nxt; } e[N*N*2];
vector<ll> vec[N],vec2[N];
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;
}
signed main()
{
    read(n); read(m); read(d);
    ll u,v,w;
    for(ll i=1;i<=m;i++)
    {
        read(u); read(v); read(w);
        add(u,v,w); add(v,u,w);
    }
	f[0][1][0]=1;
	for(ll i=0;i<(d+1)/2;i++)
	{
		for(ll j=1;j<=n;j++)
		{
			for(ll k=head[j];k;k=e[k].nxt)
			{
				for(ll s=0;s<=(1<<((d+1)/2))-1;s++)
				{
					f[i+1][e[k].v][(s<<1)|e[k].w]|=f[i][j][s];
				}
			}
		}
	}
	for(ll i=1;i<=n;i++)
	{
		for(ll s=0;s<(1<<(d+1)/2);s++)
		{
			if(f[(d+1)/2][i][s]) 
			{
				vec[i].push_back(s);
			}
		}
	}
	memset(f,0,sizeof f);
	for(ll i=1;i<=n;i++) f[0][i][0]=1;
	for(ll i=0;i<d-(d+1)/2;i++)
	{	
		for(ll j=1;j<=n;j++)
		{
			for(ll k=head[j];k;k=e[k].nxt)
			{
				for(ll s=0;s<=(1<<(d-(d+1)/2))-1;s++)
					f[i+1][e[k].v][(s<<1)|e[k].w]|=f[i][j][s];
			}
		}
	}
	for(ll i=1;i<=n;i++)
	{
		for(ll s=0;s<=(1<<(d-(d+1)/2))-1;s++)
		{
			if(f[d-(d+1)/2][i][s]) 
			{
				vec2[i].push_back(s);
			}
		}
	}
	for(ll i=1;i<=n;i++)
	{
		for(ll j=0;j<vec[i].size();j++)
		{
			for(ll k=0;k<vec2[i].size();k++)
			{
				vis[(vec[i][j]<<(d-(d+1)/2))|vec2[i][k]]=1;
			}
		}
	}
	ll ans=0;
	for(ll i=0;i<=(1<<d)-1;i++) ans+=vis[i];
	write(ans);
    return 0;
}

C. z

让我充分认知了\(C++11\ STL\)的强大.
如果存在一个 \(x_i\) 使得 \(x_i−1 = x_i\)\(x_i−1 < x_i < x_i+1\)\(x_i−1 > x_i > x_i+1\),那么可以删去它。
需要行走的路径可以表示为一正一负的位移,在 l 不超过最小的位移绝对值时,答案是一个
一次函数。
当 l 超过这个值时,意味着当我们到达一个位置时,后继位置直接被接触到,我们需要将 3
个位移合并为 1 个(当然在首尾位置时可能要特判),答案又是一个一次函数。
\(map/\)链表维护位移序列,\(priority\ queue\) 维护最小位移绝对值,离线询问即可.

C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define p() printf("Pass")
	#define ll long long int
	#define re register ll 
	#define lf double
	#define lb lower_bound 
	#define ub upper_bound 
	#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) memcpy(x,y,sizeof x);
	#define pass() printf("Pass")
	inline ll read()
	{
		ll ss=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
		while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
		return cit?ss:-ss;
	}
} using namespace BSS;


const ll N=1e5+50;

ll n,m,tot;
ll poss[N],pos[N],pre[N],nxt[N],ans[N];
map<ll,ll> maps;
struct I 
{
	ll len,id;
	bool operator <(const I &i) const
	{
		return len==i.len ? id<i.id : len<i.len ;
	}
	bool operator >(const I &i) const
	{
		return len==i.len ? id>i.id : len>i.len ;
	}
} p[N];
inline ll getans(ll x)
{
	if(maps.size() and maps.begin()->second<0) return tot-(maps.size()-1)*x;
	else return tot-maps.size()*x;
}
inline void Work()
{		
	priority_queue<I,vector<I>,greater<I> > que;
	ll tem,tmp,id,t=1; I temp;
	for(ll i=1;i<=n;i++)
	{
		tmp=pos[i]-pos[i-1];
		maps[i]=tmp; tot+=abs(tmp);
		que.push((I){abs(tmp),i});
	}
	map<ll,ll>::iterator it;
	while(que.size())
	{	
		temp=que.top(); id=temp.id; tmp=temp.len;
		que.pop(); it=maps.find(id);
		if(it==maps.end() or abs(it->second)!=tmp) continue;
		while(t<=m and tmp>p[t].len) 
			ans[p[t].id]=getans(p[t].len),t++;
		if(it==maps.begin())
		{
			if(maps[id]<=0) continue;
			if(it==prev(maps.end()))
			{
				maps.erase(it);
				tot-=tmp;
			}
			else
			{
				tmp=next(it)->second;
				maps.erase(next(it)); 
				tot+=-abs(tmp)-abs(it->second);
				if(tmp+(it->second)) 
				{
					maps[id]=tmp+(it->second); tot+=abs(maps[id]);
					que.push((I){abs(maps[id]),id});
				}
				else maps.erase(it);
			}
		}
		else 
		{
			if(it==prev(maps.end()))
			{
				maps.erase(it);
				tot-=tmp;
			}
			else
			{
				tmp=next(it)->second+it->second+prev(it)->second;
				tot+=abs(tmp)-abs(next(it)->second)-abs(it->second)-abs(prev(it)->second);
				maps.erase(next(it)); maps.erase(prev(it));
				maps[it->first]=tmp;
				que.push((I){abs(tmp),it->first});
			}
		}
	}
	while(t<=m)
		ans[p[t].id]=getans(p[t].len),t++;
	return ;
}	
signed main()
{
	n=read(); m=read();
	for(ll i=1;i<=n;i++) poss[i]=read();
	ll temp=0;
	for(re i=1;i<=n;i++)
		if(poss[i]!=poss[i-1]) pos[++temp]=poss[i];
	Fill(poss,0); Copy(poss,pos); Fill(pos,0);
	n=temp,temp=0;
	for(re i=1;i<=n-1;i++)
	{
		if(poss[i]>pos[temp] and poss[i]<poss[i+1]) continue;
		if(poss[i]<pos[temp] and poss[i]>poss[i+1]) continue;
		pos[++temp]=poss[i];
	}
	pos[++temp]=poss[n];
	n=temp;
	for(re i=1;i<=m;i++) p[i].len=read(),p[i].id=i;
	sort(p+1,p+1+m);
	Work();
	for(re i=1;i<=m;i++) printf("%lld\n",ans[i]);
	return 0;
}
// 高超的删减技术:除去无用的、合并冗余的..       
posted @ 2021-08-05 19:55  AaMuXiiiiii  阅读(27)  评论(0编辑  收藏  举报