【原创】2019.10.26模拟赛 Adore Confess Repulsed

0 说在前面

看完题就感觉这出题人为造比赛强出题,或者就是从cf上搬来的题。

1 Adore

1.1 问题描述

小 w 偶然间见到了一个 DAG。
这个 DAG 有 m 层,第1层只有1个源点,最后1层只有1个汇点,剩下的每1层都有 k 个节点。
现在⼩ w 每次可以取反第 i(1 < i < n − 1 n-1 n1) 层和第 i + 1 层之间的连边。也就是把原本从(i, k 1 _1 1) 连到 (i + 1, k 2 _2 2) 的边,变成从 (i, k 2 _2 2) 连到 (i + 1, k 1 k_1 k1)。
请问他有多少种取反的⽅案,把从源点到汇点的路径数变成偶数条?
答案对 998244353 取模。

1.2 输入格式

一行两个整数 m, k。
接下来 m-1 行, 第一行和最后一行有 k 个整数 0 或 1,剩下每行有 k 2 ^2 2 个整数 0 或 1,第(j-1) × k + t 个整数表示 (i, j) 到 (i + 1, t) 有没有边。

1.3 输出格式

一行一个整数表示答案。

1.4 样例输入

5 3
1 0 1
0 1 0 1 1 0 0 0 1
0 1 1 1 0 0 0 1 1
0 1 1

1.5 样例输出

4

1.6 数据规模与约定

20% 的数据满⾜ n ≤ 10, k ≤ 2
40% 的数据满⾜ n ≤ 1 0 3 10^3 103, k ≤ 2。
60% 的数据满⾜ m ≤ 1 0 3 10^3 103, k ≤ 5。
100% 的数据满⾜ 4 ≤ m ≤ 1 0 4 10^4 104, k ≤ 10。

1.7 分析咕咕咕,只有吐槽

多谢出题人手下留情。

1.8 代码

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

inline void Read(int &p)
{
	p=0;
	char c=getchar();
	while(c<'0' || c>'9') c=getchar();
	while(c>='0' && c<='9')
		p=p*10+c-'0',c=getchar();
}

const int MAXN=10234,MAXK=14,MAXS=1044,mod=998244353;
int n,m,a,two[MAXK],f[MAXN][MAXK],g[MAXN][MAXK],dp[MAXN][MAXS];

int main()
{
	freopen("adore.in","r",stdin);
	freopen("adore.out","w",stdout);
	
	two[0]=1; for(int i=1;i<MAXK;i++) two[i]=two[i-1]*2;
	
	Read(n),Read(m);
	for(int i=1;i<=m;i++) Read(a),f[1][1]+=a*two[i-1];
	for(int i=2;i<=n-2;i++) 
		for(int j=1;j<=m;j++)
			for(int k=1;k<=m;k++) 
				Read(a),f[i][j]+=a*two[k-1],g[i][k]+=a*two[j-1];
	for(int i=1;i<=m;i++) Read(a),f[n-1][i]+=a;
	
	dp[1][1]=1;
	for(int i=1;i<=n-1;i++)
		for(int j=0,tmp;j<=two[m]-1;j++)
			if(dp[i][j])
			{
				tmp=0; for(int k=1;k<=m;k++) tmp^=f[i][k]*bool(two[k-1]&j);
				dp[i+1][tmp]=(1ll*dp[i+1][tmp]+dp[i][j])%mod;
				if(i==1 || i==n-1) continue;
				tmp=0; for(int k=1;k<=m;k++) tmp^=g[i][k]*bool(two[k-1]&j);
				dp[i+1][tmp]=(1ll*dp[i+1][tmp]+dp[i][j])%mod;
			}
    printf("%d\n",dp[n][0]);
}

2 Confess

2.1 问题描述

小w 隐藏的心绪已经难以再隐藏下去了。
小w 有 n + 1(保证 n 为偶数) 个心绪,每个都包含了 [1, 2n] 的⼀个⼤⼩为 n 的子集。
现在他要找到隐藏的任意两个心绪,使得他们的交小于等于 n2。

2.2 输入格式

一行一个整数 n。
接下来每行一个长度为 k 的字符串,该字符串是一个 64 进制表示,ASCII 码为 x 的字符代表着 x-33,所有字符在 33 到 33 + 63 之间。
转为二进制表示有 6k 位,它的前 2n 个字符就是读入的集合,第 i 位为 1 表示这个集合包含 i,为 0 表示不包含。

2.3 输出格式

一行两个不同的整数表示两个集合的编号。
如果无解输出”NO Solution”。

2.4 样例输入

10
EVK#
IH=#
676"
R7,#
74S"
6V2#
O3J#
S-7$
NU5"
C[$$
3N.#

2.5 样例输出

1 2

2.6 数据规模与约定

对于 20% 的数据满足 n ≤ 100。
对于 50% 的数据满足n ≤ 1 × 10 3 ^3 3
对于 100% 的数据满足 n ≤ 6 × 10 3 ^3 3

2.7 分析咕咕咕,只有吐槽

我佛了。
看到随机化的题我就佛一次。
我佛了。
找alster大佬学了bitset。

2.8 代码

#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

char s[6666];
bitset<12006>a[6006];
int n,tmp,len,two[66];
#define lowbit(x) (x&(-(x)))

int main()
{
	freopen("confess.in","r",stdin);
	freopen("confess.out","w",stdout);
	
	scanf("%d",&n),n++;
	two[1]=0,two[2]=1,two[4]=2,two[8]=3,two[16]=4,two[32]=5,two[64]=6;
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		if(!len) len=strlen(s+1),tmp=64-(1<<(6*len-2*n));
		s[len]=char(((s[len]-33)&tmp)+33);
		
		for(int j=1,k=0;j<=len;j++)
		{
			s[j]-=33;
			while(s[j]) a[i].set(k+two[lowbit(s[j])]),s[j]-=lowbit(s[j]);
			k+=6;
		}
	}
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			if(int((a[i]&a[j]).count())>=(n>>1|1))
				return printf("%d %d",i,j),0;
	printf("NO Solution");
}

3 Repulsed

3.1 问题描述

小 w 心中的火就要被熄灭了。
简便起见,假设小 w 的内心是一棵 n-1 条边,n 个节点的树。
现在你要在每个节点放一些个灭火器,每个节点可以放任意多个。
接下来每个节点都要被分配给一个至多 k 条边远的灭火器,每个灭火器最多能分配给 s 个节点。
至少要多少个灭火器才能让小 w 彻底死亡呢?

3.2 输入格式

第三个整数 n, s, k。
接下来 n-1 行每行两个整数表示一条边。

3.3 输出格式

一行一个整数表示答案

3.4 样例输入

10 10 3
1 8
2 3
1 5
2 4
1 2
8 9
8 10
5 6
5 7

3.5 样例输出

1

3.6 数据规模与约定

对于 20% 的数据满足 n ≤ 100, k ≤ 2。
对于另外 20% 的数据满足 k = 1。
对于另外 20% 的数据满足 s = 1。
对于 100% 的数据满足 n ≤ 10 5 ^5 5, k ≤ 20, s ≤ 10 9 ^9 9

3.8 代码

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

inline void Read(int &p)
{
	p=0;
	char c=getchar();
	while(c<'0' || c>'9') c=getchar();
	while(c>='0' && c<='9')
		p=p*10+c-'0',c=getchar();
}

const int MAXN=102030,MAXM=202030,LOG=22;
int n,s,k,u,v,cnt,ans,ark,vis[MAXN],head[MAXN],to[MAXM],nxt[MAXM],f[MAXN][LOG],g[MAXN][LOG];

inline void addedge(int u,int v){nxt[++cnt]=head[u],head[u]=cnt,to[cnt]=v;}
void dfs(int pos)
{
	vis[pos]=1;
	for(int i=head[pos];i;i=nxt[i])
		if(!vis[to[i]])
		{
			dfs(to[i]);
			for(int j=1;j<=k;j++) f[pos][j]=min(f[pos][j]+f[to[i]][j-1],n),g[pos][j]+=g[to[i]][j-1];
		}
	g[pos][0]=1;
	if(g[pos][k]) ans+=(ark=(g[pos][k]==0?0:(g[pos][k]-1)/s+1)),f[pos][0]=min(1ll*n,1ll*s*ark);
	for(int i=0;i<=k;i++) ark=min(f[pos][i],g[pos][k-i]),f[pos][i]-=ark,g[pos][k-i]-=ark;
	for(int i=0;i<k;i++) ark=min(f[pos][i],g[pos][k-i-1]),f[pos][i]-=ark,g[pos][k-i-1]-=ark;
}
int main()
{
	freopen("repulsed.in","r",stdin);
	freopen("repulsed.out","w",stdout);
	Read(n),Read(s),Read(k);
	for(int i=2;i<=n;i++) Read(u),Read(v),addedge(u,v),addedge(v,u);
	dfs(1);
	for(int i=k;i>=1;i--)
		for(int j=0;i+j<=k;j++)
			ark=min(f[1][i],g[1][j]),f[1][i]-=ark,g[1][j]-=ark;
	ark=0;
	for(int i=0;i<=k;i++) ark+=g[1][i];
	ans+=(ark==0?0:(ark-1)/s+1);
	printf("%d\n",ans);
}

4 说在后面

咋感觉自己像个营销号或者爬虫号一样呢?
hub.io/flowchart.js/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值