2021.11.6考试总结[冲刺NOIP模拟24]

T1 破门而入

就是个第一类斯特林数行求和。

\(code:\)

T1
#include<bits/stdc++.h>
using namespace std;

namespace IO{
	typedef long long LL; typedef long double LD;
	typedef unsigned long long ULL; typedef double DB;
	int read(){
		int x=0,f=1; char ch=getchar();
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	}
	void write(int x,char sp){
		char ch[20]; int len=0;
		if(x<0) x=-x,putchar('-');
		do{ ch[len++]=x%10+'0'; x/=10; }while(x);
		for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
	}
	void ckmin(int& x,int y){ x=x<y?x:y; }
	void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO;

const int NN=3010,mod=998244353;
int n,k,ans;
int s[NN][NN];

signed main(){
	freopen("broken.in","r",stdin);
	freopen("broken.out","w",stdout);
	n=read(); k=read();
	s[0][0]=1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=i;j++)
			s[i][j]=(1ll*(i-1)*s[i-1][j]%mod+s[i-1][j-1])%mod;
	for(int i=1;i<=k;i++) ans=(ans+s[n][i])%mod;
	write(ans,'\n');
	return 0;
}

T2 翻转游戏

用总方案减去不合法方案。长度不为一的不合法方案即为首尾相同的子串个数。

\(code:\)

T2
#include<bits/stdc++.h>
#define int long long
using namespace std;

namespace IO{
	typedef long long LL; typedef long double LD;
	typedef unsigned long long ULL; typedef double DB;
	int read(){
		int x=0,f=1; char ch=getchar();
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	}
	void write(int x,char sp){
		char ch[20]; int len=0;
		if(x<0) x=-x,putchar('-');
		do{ ch[len++]=x%10+'0'; x/=10; }while(x);
		for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
	}
	void ckmin(int& x,int y){ x=x<y?x:y; }
	void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO;

const int NN=3000010;
int n,ans,buc[26];
char s[NN];

signed main(){
	freopen("turn.in","r",stdin);
	freopen("turn.out","w",stdout);
	scanf("%s",s+1); n=strlen(s+1);
	ans=(n+1)*n/2-n+1;
	for(int i=1;i<=n;i++){
		ans-=buc[s[i]-'a'];
		++buc[s[i]-'a'];
	}
	write(ans,'\n');
	return 0;
}

T3 奶油蛋糕塔

奶油一共 \(10\) 种组合,对于首尾不同的蛋糕,每奇数个相同的蛋糕可以看作一个将他们拼起来且状态一样的大蛋糕,首尾相同的可以直接合并。那么合并完后至多有 \(20\) 个蛋糕。直接状压。

\(code:\)

T3
#include<bits/stdc++.h>
using namespace std;

namespace IO{
	typedef long long LL; typedef long double LD;
	typedef unsigned long long ULL; typedef double DB;
	int read(){
		int x=0,f=1; char ch=getchar();
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	}
	void write(int x,char sp){
		char ch[20]; int len=0;
		if(x<0) x=-x,putchar('-');
		do{ ch[len++]=x%10+'0'; x/=10; }while(x);
		for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
	}
	void ckmin(int& x,int y){ x=x<y?x:y; }
	void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO;

const int NN=500010;
int n,ans,d[NN],typ[NN][2];
vector<int>buc[4][4];
int tot,f[1<<20][4];
struct Data{
	int d,up,dn;
	Data(){}
	Data(int a,int b,int c){ d=a; up=b; dn=c; }
}p[NN];
char ch;

signed main(){
	freopen("cake.in","r",stdin);
	freopen("cake.out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++){
		d[i]=read();
		cin>>ch; typ[i][0]=(ch=='X')?0:((ch=='Y')?1:((ch=='Z')?2:3));
		cin>>ch; typ[i][1]=(ch=='X')?0:((ch=='Y')?1:((ch=='Z')?2:3));
		if(typ[i][0]>typ[i][1]) swap(typ[i][0],typ[i][1]);
		buc[typ[i][0]][typ[i][1]].push_back(d[i]);
	}
	for(int i=0;i<4;i++)
		for(int j=i;j<4;j++) if(buc[i][j].size()){
			sort(buc[i][j].begin(),buc[i][j].end());
			p[++tot]=Data(0,i,j);
			for(int k:buc[i][j]) p[tot].d+=k;
			if(!(buc[i][j].size()&1)&&i!=j)
				p[tot].d-=buc[i][j][0],p[++tot]=Data(buc[i][j][0],i,j);
		}
	memset(f,0xc0,sizeof(f));
	f[0][0]=f[0][1]=f[0][2]=f[0][3]=0;
	for(int i=0;i<(1<<tot);i++)
		for(int j=0;j<4;j++) if(f[i][j]>=0){
			for(int k=1;k<=tot;k++) if(!(i&(1<<k-1))){
				if(p[k].up==j) ckmax(f[i|(1<<k-1)][p[k].dn],f[i][j]+p[k].d);
				if(p[k].dn==j) ckmax(f[i|(1<<k-1)][p[k].up],f[i][j]+p[k].d);
			}
			ckmax(ans,f[i][j]);
		}
	write(ans,'\n');
	return 0;
}

T4 多重影分身之术

答案有单调性,可以二分。

每个 \(x\) 的路径不会相交, \(check\) 时单调指针扫 \(y\) ,每个 \(x\) 处理它左侧还未处理的所有 \(y\) ,之后尽量向右处理,最后看 \(y\) 能否处理完即可。

\(code:\)

T4
#include<bits/stdc++.h>
using namespace std;

namespace IO{
	typedef long long LL; typedef long double LD;
	typedef unsigned long long ULL; typedef double DB;
	int read(){
		int x=0,f=1; char ch=getchar();
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	}
	void write(int x,char sp){
		char ch[20]; int len=0;
		if(x<0) x=-x,putchar('-');
		do{ ch[len++]=x%10+'0'; x/=10; }while(x);
		for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
	}
	void ckmin(int& x,int y){ x=x<y?x:y; }
	void ckmax(int& x,int y){ x=x>y?x:y; }
} using namespace IO;

const int NN=300010;
int n,m,x[NN],y[NN];
int l,r,ans;

bool check(int tim){
	int it=0;
	for(int i=1;i<=n;i++){
		int las=it+1;
		if(tim<abs(x[i]-y[las])&&x[i]>y[las]) return 0;
		while(y[it+1]<x[i]) ++it;
		if(y[las]>x[i]) while(tim>=y[it+1]-x[i]&&it<m) ++it;
		else while(tim>=min(2*(x[i]-y[las])+y[it+1]-x[i],x[i]-y[las]+2*(y[it+1]-x[i]))&&it<m) ++it;
		if(it==m) return 1;
	}
	return 0;
}

signed main(){
	freopen("duplication.in","r",stdin);
	freopen("duplication.out","w",stdout);
	n=read(); m=read();
	for(int i=1;i<=n;i++) x[i]=read();
	for(int i=1;i<=m;i++) y[i]=read();
	sort(x+1,x+n+1); sort(y+1,y+m+1);
	r=1.1e9;
	while(l<=r){
		int mid=l+r>>1;
		if(check(mid)) ans=mid,r=mid-1;
		else l=mid+1;
	}
	write(ans,'\n');
	return 0;
}
posted @ 2021-11-06 16:43  keen_z  阅读(59)  评论(1编辑  收藏  举报