2021.10.18模拟总结

心路历程&&过程

\(CSP\) 之前最大的一次翻车,很警醒。
由于请了大概一周的病假,急于想拿高分。虽然也想着谨慎,但看来还是没稳住。

过程

  • \(13:40\) 开始。
  • \(14:00\) 通读完毕。
  • \(14:15\) \(T1\) 打完部分分(\(40\)),但没有充分验证。同时开始推 \(T1\) 的正解。
  • \(15:15\) 大概想出 \(T1\) 接近正解的做法,但尝试之后发现细节繁多实现复杂,没有把握短时间写完,转而看 \(T2\)
  • \(15:45\) 本来想 \(T2\) 暴力,但是想出正解,写完+验证完(埋下伏笔)。此时心情愉悦,感觉胜券在握。同时计划 \(16:25\) 写完 \(T3\) 部分分。
  • \(16:25\) 因为推着推着开始想 \(T3\) 正解,所以还没打部分分。此时不想放弃,继续推。
  • \(16:40\) 刚刚推完式子,打完之后 \(WA\) 了。此时想再推推。
  • \(17:00\) 检查出一些错误,但还是不对。觉得此时时间所剩不多(\(40min\)),觉得再去打暴力此题必定没时间改,有点犹豫。
  • \(17:40\) 随着时间推移,更加不能去做其他的题(做了就相当于放任本题爆零),相信奇迹然而并没有发生。最终饮恨当场。

赛后实际

\(0+60+10+0=70pts\)
基本把能遇到的问题都试了一遍。
首先是 \(T1\) 由于部分分没有充分验证,而且最后心态有点急,所以多测清空不彻底+忘记打freopen
\(T2\) 有点太得意忘形了,过程量忘开 \(longlong\) 爆掉。
\(T3\) 的问题最大,部分分应该先打出来对着拍,剩下 \(1h\) 应该先写个暴力再回来看。最好是按照自己的计划来,先打暴力。
\(T4\) 根本没做,,没什么可说的。

问题

  • \(T1\) 用时略长,应该总用时 \(70min\) 左右换下脑子。
  • \(T2\) 不够仔细。
  • \(T3\) 没有按照计划做。

题解

T1 卡牌游戏

经过一番思考之后发现 dfs 的复杂度就能过,关键在于怎么判断所有卡牌都确定。
两种方法:

  • 方法1:对于两张不完全相同的牌,都存在一个提示能区分开它们,则说明所有卡牌均确定。
    感性理解就是牌能两两区分开,看似简单然而不好想。
  • 方法2:每次获得一个提示,相当于给对应的位置覆盖上一种标记。当每个位置的标记都不同时即可区分。
    具体实现通过二进制的唯一分解,标记分别记录为 \(1,2,4,8,16,32...2^n\) ,这样不同标记叠加产生的效果一定是不同的。

代码

点击查看代码

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f,N = 105;
#define ll long long 
inline ll read()
{
	ll ret=0;char ch=' ',c=getchar();
	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ch=='-'?-ret:ret;
}
int n,col[N],num[N];
int ans=INF;
bool vis[16];
char s[N][4];
inline bool check()
{
	for(int i=1;i<=n;i++)	
		for(int j=i+1;j<=n;j++)	
		{
			if(col[i]==col[j]&&num[i]==num[j]) continue;
			if(col[i]==col[j])
			{
				if(!vis[num[i]]&&!vis[num[j]]) return false;
			}
			else if(num[i]==num[j]) 
			{
				if(!vis[col[i]]&&!vis[col[j]]) return false;
			}
			else if(!vis[col[i]]&&!vis[col[j]]&&!vis[num[i]]&&!vis[num[j]]) return false;
		}
	return true;
}
void dfs(int stp,int cnt)//stp从1开始 
{
	if(check()) {ans=min(ans,cnt);return;}	
	if(stp>14) return;
	dfs(stp+1,cnt);
	vis[stp]=1;
	dfs(stp+1,cnt+1);
	vis[stp]=0;
}

int main()
{
	int T=read();
	while(T--)
	{
		n=read(); ans=INF;
		for(int i=1;i<=n;i++) 
			scanf("%s",s[i]+1),col[i]=s[i][1]-'A'+1,num[i]=s[i][2]-'0'+7;
		//for(int i=1;i<=n;i++) printf("%d %d %d %d\n",col[i],num[i],s[i][1],s[i][2]);
		dfs(1,0);
		printf("%d\n",ans);
	}
	return 0;
}
/*
2
2
A3 A3
4
A4 B4 B3 C3
*/

T2 道路负荷

考场切了,但因为 int 相乘爆 int 丢了 \(40pts\),是惨痛的教训。

T3 矩阵填数

整场考试崩盘的源泉。
题解给的是容斥做法,不好理解,不好想,不好推,不好写,所以暂时放弃。
隔壁 \(\mathtt{Hanoist}\) 提供了一种易懂的方法。
做法直接写在代码注释里了。

代码

点击查看代码

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f,mod = 998244353,N = 5005;
#define ll long long
inline ll read()
{
	ll ret=0;char ch=' ',c=getchar();
	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ch=='-'?-ret:ret;
}
int n;
ll w[N];
ll fac[N*N],ifac[N*N];
ll dp[2][N];
//dp[i][j]表示前i个数字总共放在j行的方案数,其中第一维用滚动数组滚掉了 
ll qpow(ll x,ll y)
{
	ll ret=1LL;
	while(y)
	{
		if(y&1) ret=ret*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ret;
}
inline ll C(int n,int m){return fac[n]*ifac[m]%mod*ifac[n-m]%mod;}
inline ll A(int n,int m){return fac[n]*ifac[n-m]%mod;}
void deal_fac()
{
	fac[0]=fac[1]=1;
	for(int i=2;i<=n*n;i++) fac[i]=fac[i-1]*i%mod;
//	printf("fac[9]=%lld\n",fac[9]);
	ifac[n*n]=qpow(fac[n*n],mod-2);
	for(int i=n*n-1;i>=0;i--) ifac[i]=ifac[i+1]*(i+1)%mod; 	
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++) w[i]=read();
	deal_fac();
	ll ans=0LL;
	dp[0][0]=1;//初始化 
	for(int i=1;i<=n;i++)	
	{
		for(int j=1;j<=i;j++)
		{
			if(j>1) dp[1][j]=(dp[0][j-1]*n*j%mod+dp[0][j]*(j*n-i+1)%mod)%mod;
			/*两个转移的情况分别是:
				1:新放一行,那么这行相对于原本j-1行有j个位置,每行有n个位置,所以dp[0][j-1]*n*j
				2:放在前面,那么前面本来有j*n个位置,放了(i-1)个数,所以是dp[0][j]*(j*n-i+1) */ 
			else dp[1][j]=A(n,i);//第一行没法正常转移,相当于初始值(而且由于滚动数组没办法用别的方法初始化) 
		}
		for(int j=1;j<=i;j++) dp[0][j]=dp[1][j];//滚动到下一层 
	}
	for(int i=1;i<=n;i++) dp[1][i]=dp[1][i]*C(n,i)%mod;//乘上没考虑的组合数 
	for(int i=1;i<=n;i++)	
		ans=(ans+dp[1][i]*w[i]%mod*fac[n*n-n])%mod;//剩下的位置全排列 
	printf("%lld\n",ans);
	return 0;
}
/*
10
8 8 6 6 4 5 11 17 21 44
*/

T4 游走

笑死,根本没做。
题解高斯消元直接劝退。

posted @ 2021-10-18 08:03  conprour  阅读(46)  评论(0编辑  收藏  举报