Loading

noip模拟44

A. Emotional Flutter

自己乱搞搞了\(50pts\),以为自己的复杂度是\(O(n)\),但其实已经接近\(O(W)\).

乱搞代码
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define ll long long int
	#define ull unsigned ll 
	#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);
	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=5e5+51;

ll Ts,n,m,r,t,cnt,alls,print;
struct I { ll l,r,len,col; } p[N];
set<pair<ll,ll> > s;
inline void Pre(){
	s.clear();
	for(re i=0;i<=n+1;++i) p[i].l=0,p[i].r=0,p[i].col=0,p[i].len=0;
	alls=0,cnt=0,print=0;
	return ;
}
inline void Init(){
	r=read(),t=read(),n=read(); ll temp=r-1,flag;
	p[1].l=1; p[0].col=1; flag=((n&1)^1);
	if(flag) --n;
	for(re i=1;i<=n;++i){
		temp+=read(); if(temp<=0) { temp+=r-1; continue; }
		if(p[cnt].col!=((i&1)^1)) ++cnt;
		p[cnt].len+=temp,p[cnt].col=(i&1)^1;
	//	if(p[cnt].col) p[cnt].len%=t;
		p[cnt].r=p[cnt].l+p[cnt].len-1,p[cnt+1].l=p[cnt].r+1;
		if(i&1) temp=1-r; else temp=r-1;
	}
	if(flag) read();
	n=cnt;
	for(re i=1;i<=n;++i){
		alls+=p[i].len;
		if((!p[i].col) and p[i].len>=t){	
			puts("NIE"); print=1;
		}
	//	cout<<p[i].l<<' '<<p[i].r<<' '<<p[i].len<<' '<<p[i].col<<'\n';
	}
//	cout<<"\n\n";
	return ;
}
inline void Work(){	
	if(print) return ;
	s.insert(mp(0,t));
	ll i=1,bz; pair<ll,ll> tmp,temp;
	while(i<=n and s.size()){
	//	cout<<tmp.first<<' '<<tmp.second<<' '<<p[i].l<<' '<<p[i].r<<endl;
		if(s.empty()){ puts("NIE"); return ; }
		if(!p[i].col) { ++i; continue; }
		tmp=*s.begin();
		if(tmp.second>alls) { puts("TAK"); return ; }
		if(p[i].l>tmp.second) { s.erase(tmp); continue; }
		if(p[i].r<tmp.first) { ++i; continue; }
		if(p[i].l>=tmp.first and p[i].r<=tmp.second){
			bz=(tmp.second-p[i].r)/t+1;
			temp.first=p[i].l+t*bz,temp.second=p[i].r+t*bz;
			s.insert(temp); ++i;
			continue;
		}
		if(tmp.first>=p[i].l and tmp.second<=p[i].r){
			bz=(p[i].r-tmp.second)/t+1;
			temp.first=tmp.first+t*bz,temp.second=tmp.second+t*bz;
			s.insert(temp); s.erase(tmp);	
			continue;
		}
		if(p[i].l<=tmp.first and p[i].r<=tmp.second and p[i].r>=tmp.first){
			bz=(tmp.second-p[i].r)/t+1;
			temp.first=tmp.first+t*bz,temp.second=p[i].r+t*bz;
			s.insert(temp); ++i; 
			continue; 
		}
		if(tmp.first<=p[i].l and tmp.second<=p[i].r and tmp.second>=p[i].l){
			bz=(p[i].r-tmp.second)/t+1;
			temp.first=p[i].l+t*bz,temp.second=tmp.second+t*bz;
			s.insert(temp); s.erase(tmp);
			continue;
		}
	}
	if(s.begin()==s.end()){
		if((*s.end()).second>alls) puts("TAK");
		else puts("NIE");
	}
	else{
		if((*(--s.end())).second>alls) puts("TAK");	
		else puts("NIE"); 
	}
	return ;
}
signed main(){
	Ts=read();
	while(Ts--){
		Pre();
		Init(),Work();
	}
	return 0;
}

思路来自 MAX_QAQ.

首先把脚的长度累计到黑块上.

对于长度\(\geq k\)的黑块,直接表明本题无解.

起点只有\(k\)个,每个黑块对于对于这些起点均有贡献,可以选择\(mod\ k\)计算.

A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define ll long long int
	#define ull unsigned ll 
	#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);
	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=5e5+51;

ll Ts,n,m,r,t,cnt,alls;
struct I { ll l,r,len,col; } p[N];
pair<ll,ll> e[N];
inline void Pre(){
	for(re i=0;i<=n+1;++i) p[i].l=0,p[i].r=0,p[i].col=0,p[i].len=0;
	for(re i=0;i<=cnt+1;++i) e[i].first=0,e[i].second=0;
	alls=0,cnt=0;
	return ;
}
inline void Init(){
	r=read(),t=read(),n=read(); ll temp=r-1,flag;
	p[1].l=1; p[0].col=1; flag=((n&1)^1);
	if(flag) --n;
	for(re i=1;i<=n;++i){
		temp+=read(); if(temp<=0) { temp+=r-1; continue; }
		if(p[cnt].col!=((i&1)^1)) ++cnt;
		p[cnt].len+=temp,p[cnt].col=(i&1)^1;
		p[cnt].r=p[cnt].l+p[cnt].len-1,p[cnt+1].l=p[cnt].r+1;
		if(i&1) temp=1-r; else temp=r-1;
	}
	if(flag) read(); n=cnt;
}
inline void Work(){
	cnt=0; ll l,r;
	for(re i=1;i<=n;++i){
		if(!p[i].col){
			if(p[i].len>=t) { puts("NIE"); return ; }
			l=p[i].l%t,r=p[i].r%t;
			if(l>r){
				e[++cnt].first=0,e[cnt].second=r,
				e[++cnt].first=l,e[cnt].second=t-1;
			}
			else e[++cnt].first=l,e[cnt].second=r;
		}
	}
	sort(e+1,e+1+cnt); r=-1;
//	for(re i=1;i<=cnt;++i) cout<<e[i].first<<' '<<e[i].second<<endl;
	if(e[1].first!=0) {puts("TAK"); return ;}
	for(re i=1;i<=cnt;i++){
		if(e[i].first>r+1){
			puts("TAK"); return ;
		}
		else{
			r=max(e[i].second,r);
		}
	}
	if(r<t-1) puts("TAK");
	else puts("NIE"); 
	return;
}
signed main(){
	Ts=read();
	while(Ts--){
		Pre();
		Init(),Work();
	}
	return 0;
}

B. Medium Counting

这类的方案数题应该一看就是动态规划了.

考虑按位统计即可.

\(dp_{i,j,st,en}\) 为转移到第 \(i\) 位,其中 \([st,en]\) 区间内至少是字母 \(j\) 的方案数.

首先有 \(dp\) 转移方程:

\[dp_{i,j,st,en}=\sum_{k=st}^{en} dp_{i+1,0,st,k}*dp_{i,j+1,k+1,en} \]

我们考虑强制 \([st,k]\) 选择了 \(j\) 字符,

\([k+1,en]\) 至少选择 \([j+1]\) 字符,

那么下一列的 \([st,k]\) 就可以自由选择了,

因为字典序以高位为优先.

B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define ll long long int
	#define ull unsigned ll 
	#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)
	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 mod=990804011;
char s[23];

ll m,n;
ll c[55][23];
ll dp[23][29][55][55];
signed main(){
	n=read(); ll tmp;
	for(re i=1;i<=n;i++){
		scanf("%s",s+1),m=max(m,tmp=strlen(s+1));
		for(re j=1;j<=tmp;j++){
			c[i][j]=s[j]-'a'+1;
			if(s[j]=='?') c[i][j]=27;
		}
	}
	for(re i=1;i<=m;i++){
		for(re j=0;j<=27;j++)
			for(re k=1;k<=n+1;k++)
				for(re h=0;h<k;h++)
					dp[i][j][k][h]=1;
	}
	for(re i=0;i<=n+1;i++) dp[m+1][0][i][i]=1;
	for(re i=m;i>=1;i--){
		for(re j=26;j>=0;j--){
			for(re l=1;l<=n;l++)
				for(re st=1,en=st+l-1;en<=n;st++,en++){
					dp[i][j][st][en]+=dp[i][j+1][st][en];
					for(re k=st;k<=en;k++){
						if(c[k][i]!=j and c[k][i]!=27) break;
						if(c[k][i]==27 and (!j)) break;
						dp[i][j][st][en]=(dp[i][j][st][en]+dp[i+1][0][st][k]*dp[i][j+1][k+1][en]%mod)%mod;
					}
				}
		}
	}
	printf("%lld\n",dp[1][0][1][n]);
	exit(0);
}

C. Huge Counting

可以看成当前 \(x\) 全部变成 \(1\) 的途径的个数其实就是当前的 \(f\) 的值.

考虑进一步简化问题,把途径个数看成方案数,那就是个可重集排列,即\(\dfrac{(\sum_{x_i})!}{\prod\limits(x_i!)}\).

想要求这个东西的奇偶性,发现其实就是求 \(\sum\limits_i({\dfrac{\sum x_j}{2^i}}-\sum\limits {\dfrac{x_j}{2^i}})\).

对于如何求阶乘里面某个质因子 \(p\) 被乘了多少次的方法就比较基础了.
(上面这句话的意思就是,设对于 \(w=n!\)\(w\) 在除以 \(x\)\(p\) 之后和 \(p\) 互质,求 \(x\).)

对于本题来说就是对于每个 \(x\) 在二进制表达下,同一位上最多只有一个 \(1\).

于是数位 \(dp\) 做就行了,注意贡献的最初来源都是 \(x\) 全部等于 \(1\) 的时候,所以注意起点和终点.

C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll long long 
	#define ull unsigned ll
	#define lf long double
	#define lbt(x) (x&(-x))
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound 
	#define ub upper_bound
	#define Fill(x,y) memset(x,y,sizeof x)
	#define Copy(x,y) memcpy(x,y,sizeof x)
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	inline ll read() {
		ll w=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0; 
		while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
		return cit?w:-w;
	}
} using namespace BSS;

const ll N=10,M=52,W=1<<10,mod=990804011;

ll m,n,Ts,U;
ll L[N],R[N],num[W];
ll f[M][W],val[N][M];
ll dfs(ll now,ll S){
	if(!now) return 1; if(~f[now][S]) return f[now][S];
	ll s=0;
	for(ll i=1;i<=n;i++){
		if( ((S>>i-1)&1) and (!val[i][now]) ) s|=1<<i-1;
	}
	f[now][S]=dfs(now-1,s);
	for(ll i=1;i<=n;i++){
		if((s>>i-1)&1) continue;
		if((S>>i-1)&1) f[now][S]=(f[now][S]+dfs(now-1,s|1<<i-1))%mod;
		else f[now][S]=(f[now][S]+dfs(now-1,s))%mod; // 依旧选这一位为 1,但是没有限制了.
	}
	return f[now][S];
}
inline void Work(){
	Fill(num,0);
	ll x,res,cnt,flag; n=read(),U=(1<<n)-1,res=0; 
	for(ll i=1;i<=n;i++) L[i]=read()-1,R[i]=read()-1;
	for(ll i=1;i<=U;i++) num[i]=num[i&(i-1)]+1;
	for(ll i=0;i<=U;i++){
		flag=0;
		for(ll j=1;j<=n;j++){
			Fill(val[j],0);
			x= (((i>>j-1)&1) ? R[j] : L[j]-1) ,cnt=0;
			if(x<0) { flag=1; break; }
			for(;x;x>>=1) val[j][++cnt]=(x&1);
		}
		if(flag) continue;Fill(f,-1);
		( (num[U]&1)==(num[i]&1) ) ? res=(res+dfs(50,U))%mod : res=(res-dfs(50,U)+mod)%mod;
	}
	printf("%lld\n",res);
}
signed main(){
	Ts=read();
	while(Ts--) Work();
	exit(0);
}

D. 字符消除 2

posted @ 2021-08-19 19:54  AaMuXiiiiii  阅读(46)  评论(0)    收藏  举报