11.08 NOIP2024模拟赛#17 div1

呜呜呜,糖丸了

发现样例给的很足啊,决定用 Lemon,这样的话赛时就可以估分了……

T1

看了大概 \(5min\) 发现不会

然后就迅速码了个暴力

发现 \(A_i=B_i\) 和另一个特殊性质看起来可写

但是决定先写后面的暴力

把 T2 暴力和链写完了回来看

发现那俩性质其实就是排列组合

码了 \(20min\) 但是调了快 \(45min\)()

Lemon 上拿到了 \(45\)

两个特殊性质
	else if(fl&&n==m)
	{
		sort(b+1,b+n+1);
		ans=1;int sum=0;//用过的数
		//想了半天判有无解才发现保证有解()
		fd(i,1,n)
		{
			int npos=2*(n-i),nnum=b[i]-sum-1;//剩的空位 没选的数
			(ans*=A(nnum,npos)%mod)%=mod;//nnum 个数里选 npos 个放进去
//			cerr<<npos<<' '<<nnum<<' '<<sum<<' '<<ans<<endl;
			sum+=npos+1;
		}
		printf("%lld\n",ans);
	}
	else
	{
//		cerr<<"(m!)="<<A(m,m)<<endl;
//		cerr<<"(m!)^(n-1)="<<qpow(A(m,m),n-1)<<endl;
		printf("%lld\n",qpow(A(m,m),n-1));
		//前 n-1 行在 (i-1)*m ~ i*m-1 随便摆,最后一行不能动
		//第 i 行方案数为 (m!)
		//(m!)^(n-1)
	}

赛后 ZJY 达捞给我讲正解,一听就懂了 %%%sto ZJY orz%%%

赛时其实有想过正解,想到了 \(2\) 种情况,正解是 \(4\) 种情况

另外两种可以乘一下就行了,但赛时觉得不是很对,自己把自己 \(ban\)

正解
#include <bits/stdc++.h>
#define int long long
#define ll long long
#define fd(i,a,b) for(int i=(a);i<=(b);i=-~i)
#define bd(i,a,b) for(int i=(a);i>=(b);i=~-i)
#define endl '\n'
using namespace std;

//#define SIZE (1<<20)
//char In[SIZE],Out[SIZE],*p1=In,*p2=In,*p3=Out;
//#define getchar() (p1==p2&&(p2=(p1=In)+fread(In,1,SIZE,stdin),p1==p2)?EOF:*p1++)
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c-48);c=getchar();}
	return x*f;
}

const int N=2009,M=4e6,mod=998244353;

int n,m,a[N],b[N];
int h[M],w[M],H,W;

inline void init()
{
	n=read(),m=read();
	H=W=0;
	fd(i,1,n*m) h[i]=w[i]=0;
	fd(i,1,n) a[i]=read(),h[a[i]]=i;
	fd(i,1,m) b[i]=read(),w[b[i]]=i;
}

inline void solve()
{
	int ans=1;
	bd(i,n*m,1)
	{
		if(h[i]&&w[i]) ++H,++W;
		else if(h[i]||w[i])
		{
			if(h[i]) (ans*=W)%=mod,++H;
			if(w[i]) (ans*=H)%=mod,++W;
		}
		else (ans*=(H*W+i-n*m))%=mod;
	}
	printf("%lld\n",ans);
}

void Main()
{
	init();
	solve();
}

signed main()
{
#define FJ
#ifdef FJ
	freopen("pagoda.in","r",stdin);
	freopen("pagoda.out","w",stdout);
#else
//	freopen("pagoda/ex_pagoda4.in","r",stdin);
//	freopen("pagoda/pagoda.out","w",stdout);
#endif
// #define io
#ifdef io
	ios::sync_with_stdio(0);
	cin.tie(0);	cout.tie(0);
#endif
	
	int T=read();
	while(T--) Main();
	
	return 0;
}

T2

写的暴力和 \(k=1\) 的情况

雪月花大佬看错题但是想到了正解!%%%%%%

\(k=1\) 只需要看是不是链即可

然后正解是注意到 \(k=2\)(因为 \(k=1\) 可以特判掉),然后进行状压记搜

\(f[i][j][msk]\) 表示最后选第 \(i\) 个,倒数第二选第 \(j\) 个,选择的状态为 \(msk\)

赛后写起来不难,但是不好想到这个转化

点击查看代码
#include<cstdio>
#include<algorithm>
#include<unordered_map>
#define ll long long
#define fd(i,a,b) for(int i=(a);i<=(b);i=-~i)
#define endl '\n'

//#define SIZE (1<<20)
//char In[SIZE],Out[SIZE],*p1=In,*p2=In,*p3=Out;
//#define getchar() (p1==p2&&(p2=(p1=In)+fread(In,1,SIZE,stdin),p1==p2)?EOF:*p1++)
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c-48);c=getchar();}
	return x*f;
}

const int N=61,M=100;

int n,m,k,mod;
int e[N][N],d[N];

inline void init()
{
	n=read(),m=read(),k=read(),mod=read();
	fd(i,1,n) d[i]=0;
	fd(i,1,n) fd(j,1,n) e[i][j]=0;
	fd(i,1,m)
	{
		int x=read(),y=read();
		e[x][y]=e[y][x]=1;
		++d[x],++d[y];
	}
}

namespace SubII
{
	inline void Main()
	{
		int cnt=0,cnt2=0;
		fd(i,1,n) cnt+=(d[i]==1),cnt2+=(d[i]==2);
		if(cnt==2&&cnt2==n-2) puts("2");
		else puts("0");
	}
}

namespace SubI
{
	ll ans,Mx;
	#define __conut __builtin_popcountll
	std::unordered_map<ll,ll> f[N][N];
	inline void clear()
	{
		fd(i,1,n) fd(j,1,n)
			f[i][j].clear();
	}
	inline void add(ll &x,ll y){x=x+y<mod?x+y:x+y-mod;}
	ll F(ll msk,int x,int y)
	{
		if(f[x][y].count(msk)) return f[x][y][msk];
		if(__conut(msk)==2) return f[x][y][msk]=1;
		int cnt=0;
		fd(i,1,n) if(x!=i&&e[i][y]&&(msk>>(i-1)&1)) ++cnt;
		fd(i,1,n) if(x!=i&&y!=i&&(msk>>(i-1)&1)&&!(cnt-e[i][y]))
			add(f[x][y][msk],F(msk^(1ll<<(y-1)),i,x));
		return f[x][y][msk];
	}
	inline void Main()
	{
		Mx=1ll<<n,ans=0,clear();
		fd(i,1,n) fd(j,1,n)
			if(i!=j) add(ans,F(Mx-1,i,j));
		printf("%lld\n",ans);
	}
}

void Main()
{
	init();
	if(n==1) puts("1");
	else if(k==1) SubII::Main();
	else SubI::Main();
}

signed main()
{
#define FJ
#ifdef FJ
	freopen("paradise.in","r",stdin);
	freopen("paradise.out","w",stdout);
#else
//	freopen("C:/Users/Lenovo/Desktop/比赛/2024.11.08/data/paradise/ex_paradise8.in","r",stdin);
//	freopen("C:/Users/Lenovo/Desktop/比赛/2024.11.08/data/paradise/paradise.out","w",stdout);
#endif
// #define io
#ifdef io
	ios::sync_with_stdio(0);
	cin.tie(0);	cout.tie(0);
#endif
	
	int T=read(),ID=read();
	while(T--) Main();
	
	return 0;
}

T3

写的暴力,赛后发现字符串可能有相同的,然后暴力就挂了……

改改可以拿到十分

(据说是紫题,所以就不给正解了,给个暴力)

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define ll long long
#define fd(i,a,b) for(int i=(a);i<=(b);i=-~i)
#define bd(i,a,b) for(int i=(a);i>=(b);i=~-i)
#define endl '\n'
using namespace std;

//#define SIZE (1<<20)
//char In[SIZE],Out[SIZE],*p1=In,*p2=In,*p3=Out;
//#define getchar() (p1==p2&&(p2=(p1=In)+fread(In,1,SIZE,stdin),p1==p2)?EOF:*p1++)
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c-48);c=getchar();}
	return x*f;
}

template<typename _T,int SIZ>
struct BIT
{
	_T c[SIZ+2];
	inline void add(int x,_T y)
	{
		for(;x<=SIZ;x+=(x&-x)) c[x]+=y;
	}
	inline _T ask(int x)
	{
		_T res=0;
		for(;x;x-=(x&-x)) res+=c[x];
		return res;
	}
};

const int N=5e5+509,M=5e5+509;

int n,m,k;
//BIT<int,26> t[N];
pair<string,int> s[N];
int rnk[N];

signed main()
{
#define FJ
#ifdef FJ
	freopen("firmiana.in","r",stdin);
	freopen("firmiana.out","w",stdout);
#else
//	freopen("C:/Users/Lenovo/Desktop/比赛/2024.11.08/data/paradise/ex_paradise8.in","r",stdin);
//	freopen("C:/Users/Lenovo/Desktop/比赛/2024.11.08/data/paradise/paradise.out","w",stdout);
#endif
// #define io
#ifdef io
	ios::sync_with_stdio(0);
	cin.tie(0);	cout.tie(0);
#endif
	
	n=read(),m=read(),k=read();
	fd(i,1,n) cin>>s[i].first,s[i].second=i;
	sort(s+1,s+n+1);
	string S="#";
	int pos=0;
	fd(i,1,n)
	{
		if(s[i].first==S) rnk[s[i].second]=pos;
		else S=s[i].first,pos=i,rnk[s[i].second]=pos;
	}
	
	while(m--)
	{
		int op=read();
		if(op==1)
		{
			string P;cin>>P;
			fd(i,1,n)
			{
				fd(j,0,s[i].first.size()-1) s[i].first[j]=P[s[i].first[j]-'a'];
			}
			sort(s+1,s+n+1);
			string S="#";
			int pos=0;
			fd(i,1,n)
			{
				if(s[i].first==S) rnk[s[i].second]=pos;
				else S=s[i].first,pos=i,rnk[s[i].second]=pos;
			}
		}
		else
		{
			int x=read();
			printf("%lld\n",rnk[x]);
		}
	}
	
	return 0;
}

T4

黑题中的黑题

暴力没码,T4 最高分 \(4\) 分,为 ZJY 达捞所得 %%%

总结

  • T1 没写出来很亏
  • T2 思维题,需要练练思维了
posted @ 2024-11-08 19:44  whrwlx  阅读(12)  评论(0编辑  收藏  举报