首页 > 其他分享 >231105校内赛

231105校内赛

时间:2023-11-05 17:15:30浏览次数:36  
标签:231105 校内 卡片 int pos k2 k1 mod

T1 构造题

没啥好说的,大样例一眼出规律

#include<bits/stdc++.h>
#define N 310
using namespace std;
int n,l[N][N],r[N][N],a[N][N];
int main(){
	freopen("squ.in","r",stdin);
	freopen("squ.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n;
	if(n%2==1){
		for(int i = 1;i<=n;i++){
			for(int j = 1;j<=n;j++)
				cout<<(i+j-2)%n+1<<" ";
			cout<<"\n";
		}
	}else if(n==2) cout<<"-1";
	else{
		for(int i = 1;i<=n;i++)
			a[1][i] = i;
		swap(a[1][n],a[1][n-1]);
		for(int i = 1;i<n/2;i++)
			a[n][i] = i*2;
		for(int i = 1;n/2+i-1<n;i++)
			a[n][n/2+i-1] = 2*i-1;
		a[n][n] = n;
		for(int i = 2;i<n;i++)
			for(int j = 1;j<n;j++)
				a[i][j] = (i+j-2)%(n-1)+1;
		for(int i = 2;i<n;i++){
			a[i][n] = a[i][i-1];
			a[i][i-1] = n;
		}
		for(int i = 1;i<=n;i++){
			for(int j = 1;j<=n;j++)
				cout<<a[i][j]<<" ";
			cout<<"\n";
		}
	}
	return 0;
}

T2 括号串

首先我们可以发现规律

一个 \(1\) 操作就是将答案加当前层的括号个数(包括添加的这个)

一个 \(2\) 操作就是将答案加一并加一层,新的一层只有添加的这个

对于 \(3\) 操作而言就是删掉或恢复一个括号或者是减去或恢复一层

对于被减去的一层,我们就需要将剩下的括号添加到它的上一层去,被恢复的则相反

但是暴力实现肯定不行的,需要用数据结构来维护

我们可以发现,其实修改只有单点修改,我们需要的只是当前层的左右端点,查询就是整个的答案

那么用线段树就可以快捷的实现了

不得不说,题解中的线段树实现得挺巧妙的

#include<bits/stdc++.h>
#define N 200010
#define int long long
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
struct node{
	int ltot,rtot,tot,flag;
}t[N<<2];
int n,opt[N],pos[N];
bool vis[N];
node pushup(node x,node y){
	node ans;
	ans.ltot = (x.flag?x.ltot:x.ltot+y.ltot);
	ans.rtot = (y.flag?y.rtot:x.rtot+y.rtot);
	ans.tot = x.tot+y.tot+x.rtot*y.ltot;
	ans.flag = x.flag|y.flag;
	return ans;
}
void change(int p,int l,int r,int pos){
	if(l==r){
		if(vis[l]) t[p].tot = t[p].ltot = t[p].rtot = t[p].flag = 0;
		else{
			if(opt[l]==1)
				t[p].tot = t[p].ltot = t[p].rtot = 1,t[p].flag = 0;
			else t[p].tot = t[p].rtot = t[p].flag = 1,t[p].ltot = 0;
		}
		return ;
	}
	int mid = (l+r)>>1;
	if(pos<=mid) change(lc,l,mid,pos);
	else change(rc,mid+1,r,pos);
	t[p] = pushup(t[lc],t[rc]);
}
signed main(){
	freopen("str.in","r",stdin);
	freopen("str.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n;
	opt[0] = 1;change(1,0,n,0);
	for(int i = 1;i<=n;i++){
		cin>>opt[i];
		switch(opt[i]){
			case 1:
			case 2:{
				pos[i] = i;
				break;
			}
			case 3:{
				cin>>pos[i];
				pos[i] = pos[pos[i]];
				break;
			} 
		}
		change(1,0,n,pos[i]);
		vis[pos[i]]^=1;
		cout<<t[1].tot<<"\n";
	}
	return 0;
}

T3 博弈

考虑枚举哪一张卡片使得游戏结束,以及这张卡片在哪一行,设这是第 \(k\) 张卡片,且在第 \(i\) 行

那么这一行之外的部分对于分数是不重要的,考虑计算这种情况出现的概率,则需要满足如下要求:

  1. 在放这张卡片之前,这一行只剩一个空位
  2. 其它行没有满

那么可以做一个 \(d p: f_{i, j}\) 表示考虑了前 \(i\) 行,前 \(i\) 行中一共放了 \(j\) 张卡片的概率,枚举结束的行做 \(m\) 次这样的 \(d p\) ,复杂度为 \(\mathcal O\left((n+m)^{2} m\right)\)

这样可以得到 \(p_{i, j}\) 表示放了 \(i\) 张卡片后结束,且在第 \(j\) 行结束的概率

然后考虑计算分数的贡献,此时最后一张卡片一定在这一行,其它卡片出现的概率相等且这一行内的可能的顺序出现的概率都相等

设 \(k\) 为使游戏结束的卡片的编号,因为其它卡片出现的概率相同,可以看成在前面选 \(l_{i}-1\) 张卡片和第 \(k\) 张卡片以任意顺序排列作为分数,然后除以 \(C_{k-1}^{l_{i}-1} * l_{i}\) !

考虑期望线性性,一张卡片的贡献为它的值乘上 \(10^{s}\) ,其中 \(s\) 为这张卡片后面的卡片的字符串长度和

因为第 \(k\) 张卡片需要特殊考虑,所以计算第 \(x\) 张卡片的贡献时,考虑枚举它在这一行的 \(j\) 个位置,以及第 \(k\) 张卡片在它的哪一侧

考虑第 \(k\) 张卡片在它的左侧的情况,此时相当于在前 \(k-1\) 张卡片除去自己中选出 \(l_{i}-j\) 张放在它右侧,设 \(s^{\prime}\) 为这些卡片的字符串长度和,那么一种方案的贡献为 \(10^{s^{\prime}}\)

设 \(s^{\prime \prime}\) 为这张卡片字符串长度,那么相当于选一个放在右侧会有 \(10^{s^{\prime \prime}}\) 的贡献,所有贡献相乘

那么可以使用一个 \(d p\) 计算这个贡献。第 \(k\) 张卡片在它右侧的情况类似

因此直接的做法相当于枚举 \(x\) ,然后做 \(d p_{s, t}\) 表示考虑 \([1, s]\) 中除去第 \(x\) 张卡片,这部分选了 \(t\) 张卡片的所有方案的贡献和,最后枚举 \(j\) 算贡献,这样的复杂度看起来是 \(\mathcal O\left(n^{5}\right)\) ,但因为 \(\sum l_{i}\) 只有 \(n+m\) ,因此复杂度为 \(\mathcal O\left(n^{3}(n+m)\right)\)

注意到对于不同的 \(x\) ,要求的都是 \(d p_{k-1}\) ,只是不能选的位置不同,可以发现,先求出所有位置都能选时的 \(d p_{k-1}\) ,在要求不能选 \(x\) 时,在 \(d p\) 上做加入物品 \(x\) 时的逆操作即可得到这个值

一种简单的解释方式是,将 \(\mathrm{dp}\) 的第二维看成生成函数,则加入一个物品相当于乘上 \(1+10^{s} x\) ,那么删去这个物品相当于除去这个一次式,可以直接 \(\mathcal O(n)\) 除

时间复杂度 \(\mathcal O\left(n^{2}(n+m)\right)\)

代码实现挺恶心的

#include<bits/stdc++.h>
#define N 310
#define mod ((int)1e9+9)
#define int long long
using namespace std;
int n,m,l[N],fac[N<<1],inv[N<<1],pw[N],val[N],f[N][N],g[N][N][2],g2[N][N][2];
char s[N][N];
int ksm(int x,int y){
	int res = 1;
	while(y){
		if(y&1) res = res*x%mod;
		x = x*x%mod;
		y>>=1;
	}
	return res;
}
inline int C(int x,int y){
	return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
signed main(){
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>m;
	int sum = 0;
	for(int i = 0;i<m;i++){
		cin>>l[i];
		sum+=l[i];
	}
	for(int i = 0;i<n;i++){
		cin>>s[i];
		int x = strlen(s[i]);
		pw[i] = 1;
		for(int j = 0;j<x;j++){
			pw[i] = pw[i]*10%mod;
			val[i] = (val[i]*10+(s[i][j]-'0'))%mod;
		}
	}
	fac[0] = 1;
	for(int i = 1;i<=600;i++)
		fac[i] = fac[i-1]*i%mod;
	inv[600] = ksm(fac[600],mod-2);
	for(int i = 599;i>=0;i--)
		inv[i] = inv[i+1]*(i+1)%mod;
	int ans = 0;
	for(int i = 0;i<m;i++){
		memset(f,0,sizeof(f));
		f[0][0] = 1;
		for(int j = 0;j<m;j++)
			for(int k = 0;k<=n;k++)
				if(f[j][k])
					for(int z = l[i]*(i==j);z<=l[j]-(i!=j)&&k+z<=n;z++)
						f[j+1][k+z] = (f[j+1][k+z]+f[j][k]*C(l[j],z)%mod)%mod;
		for(int k = 0;k<=l[i];k++)
			memset(g[k],0,sizeof(g[k]));
		g[0][0][0] = 1;
		for(int j = 0;j<=sum;j++){
			if(j>=l[i]&&j<=n&&j<=sum)
				for(int k = 0;k<l[i];k++){
					int ways = fac[j-l[i]]*fac[k]%mod*fac[l[i]-k-1]%mod;
					ways = inv[sum]*fac[sum-j]%mod*ways%mod;
					ans = (ans+f[m][j]*(g[k][l[i]-k-1][1]+mod-g2[k][l[i]-k-1][1])%mod*ways)%mod;
				}
			for(int k = 0;k<=l[i];k++)
				memcpy(g2[k],g[k],sizeof(g2[k]));
			for(int k1 = l[i]-1;k1>=0;k1--)
				for(int k2 = l[i]-k1;k2>=0;k2--){
					int *tmp = g[k1][k2];
					if(g[k1][k2][1]){
						g[k1+1][k2][1] = (g[k1+1][k2][1]+tmp[1])%mod;
						g[k1][k2+1][1] = (g[k1][k2+1][1]+(pw[j]*tmp[1])%mod)%mod;
					}
					if(g[k1][k2][0]){
						g[k1+1][k2][0] = (g[k1+1][k2][0]+tmp[0])%mod;
						g[k1][k2+1][0] = (g[k1][k2+1][0]+pw[j]*tmp[0]%mod)%mod; 
						g[k1][k2][1] = (g[k1][k2][1]+val[j]*tmp[0]%mod)%mod;
					}
				}
		}
	}
	cout<<ans;
	return 0;
}

标签:231105,校内,卡片,int,pos,k2,k1,mod
From: https://www.cnblogs.com/cztq/p/17810721.html

相关文章

  • 231101校内赛
    T1茵蒂克丝模拟题,用一个栈模拟就完了,挺简单的有人没看见是非负数#include<bits/stdc++.h>#definepiipair<int,int>#definefifirst#definesesecond#defineN1000010usingnamespacestd;intn,k,a[N],ans[N],cnt,top,tot;piistk[N],b[N];boolcmp(piix,piiy){......
  • 231030校内赛
    T1新的阶乘有三种做法,第一种也就是我写的这种容易被评测机波动坑,复杂度玄学考虑处理出每个数的质因数,然后就暴力除每个数的质因数的种类次非常的简单,也容易被卡第二种是与第一种差距不大,就是在线性筛中处理出质因数之后,再对每个数除以线筛中处理的质因数,将它的答案加到除数和......
  • 231023校内赛
    T1区间题解很容易想到的一点是如果\(k\)足够大,那么把区间单独放到一个组里总比多个区间在一个组优对于多个区间来说,区间之间如果两两不包含的话这道题会是比较好做的就可以注意到如果一个大区间包含了一个小区间,那么大区间要么单独一组,要么和小区间同一组,这样会是比较优的......
  • 231019校内赛
    T1机器人题解傻逼题,但是有人\(90\)分一开始十分想直接暴力\(2^n\)判断每一步选不选求出所有可能性但是会发现它有制约关系有些步走了之后,有些就必须走了所以需要用一个数组记录当前位置走没走过,或者是不是障碍注意走没走过不能直接赋值\(1,0\)因为回溯时会直接将前......
  • 231019校内赛
    T1购买饮料题解简单且傻逼的题目有人更傻逼没做出来很容易就会想去拿最后能喝多少瓶去做未知量来求然后就有一个严重的问题,它会赊账非常明显这样算是不得行的那么考虑换个思路以能喝多少套饮料为未知量,先除去第一套,免得一套都买不起时赊账买了饮料然后将剩余的钱除以\(......
  • [校内]此方(konata)
    2023-10-14题目LittleBrother题目描述难度&重要性(1~10):7题目来源CQYC题目算法几何,二分解题思路Sol我们知道,对于两个圆,我们无非就只有三种情况:相离,相切,相交。而这道题目是不允许其他圆相交,而两个圆不相交只有两种情况:包含,不包含。根据垂径定理得知,过线段两端的圆的......
  • 231011校内赛
    T1树上的数题解比上一次好一些的第一题不过我还是没做出来一眼树形\(dp\)不过状态设计和转移不是很好列容易想到对于子树枚举,记录\(f_{i,j}\)表示\(i\)的子树空出了\(j\)个点时的方案数对于每一个节点的初始状态都是\(f_{i,0}=n-dep_i\\\f_{i,1}=1\)为......
  • 231009校内赛
    T1里群题解阴间第一题题目中有一个很明显的建图方法就是对于第\(i\)天入群的人在第\(j\)天退群那么就在\(i,j\)之间连一条边首先有一个结论,管理员个数不大于\(3\)对于这个结论,证明如下:首先第一次删除出现后就一定需要两个管理员了如果某次删除只删掉了某一个管理......
  • 231007校内赛
    T1karma题解首先从贪心的思路出发把所有零多的字符串放在前面,但如下一组数据便可以卡掉201100接着我们可以来思考对于贪心的更改多举几组不同的可以卡掉的样例后可以发现如下规律先将所有字符串按\(0\)的数量排一遍序对于每一个字符串的\(0\)和\(1\)的数量我......
  • 231004校内赛
    T1水管题解很简单的一道题,别想复杂了只要一边\(dfs\)即可先将当前点的所有水量给出去,如果缺水就给出去负数那么等到最后一个节点如果不是刚好合适,那么就把剩余水量回溯回来,无论正负再如此给下一个连边的点如果最后一个点刚好合适那么给下一个点的就是\(0\)实现很简单......