Codeforces Round 925 (Div. 3)(A,B,C,D,E,F,G)

比赛链接

这场打的很顺,感觉难度和 div 4 差不多,不是很难。D题稍微考了考同余的性质,E题直接模拟过程即可,F题也可以暴力模拟或者拓扑排序,G题是个数学题,是个简单隔板法。A到F题都可以直接模拟就有点离谱。


A. Recovering a Small String

题意:

尼基塔的单词正好由 3 3 3 个小写拉丁字母组成。拉丁字母的编号从 1 1 1 26 26 26 ,其中字母 "a "的编号为 1 1 1 ,字母 "z "的编号为 26 26 26

他将这个单词编码为字母表中所有字符的位置总和。例如,他将单词 "cat "编码为整数 3 + 1 + 20 = 24 3 + 1 + 20 = 24 3+1+20=24 ,因为字母 "c "在字母表中的索引为 3 3 3 ,字母 "a "的索引为 1 1 1 ,字母 "t "的索引为 20 20 20

然而,这种编码结果是模糊的!例如,对单词 "ava "进行编码时,也会得到整数 1 + 22 + 1 = 24 1 + 22 + 1 = 24 1+22+1=24

请找出由 3 3 3 个字母组成的字典序最小的单词。

当且仅当以下条件之一成立时,字符串 a a a 在词法上小于字符串 b b b

  • a a a b b b 的前缀,但 a ≠ b a \ne b a=b
  • a a a b b b 不同的第一个位置,字符串 a a a 的字母在字母表中出现的时间早于 b b b 中的相应字母。

思路:

显然先动后面的字母,大的字母放在后面。初始是aaa,先第三个位置上从a到z,这时 n ∈ [ 3 , 28 ] n\in[3,28] n[3,28],然后第二个位置从a到z,这时 n ∈ [ 29 , 53 ] n\in[29,53] n[29,53],最后第一个位置从a到z,这时 n ∈ [ 54 , 78 ] n\in[54,78] n[54,78]

也可以直接dfs爆搜,毕竟就三个位置。

code:

#include <iostream>
#include <cstdio>
using namespace std;int T,n;int main(){cin>>T;while(T--){cin>>n;if(n<=28)printf("aa%c\n",n-2-1+'a');else if(n<=53)printf("a%cz\n",n-1-26-1+'a');else printf("%czz\n",n-26-26-1+'a');}return 0;
}

B. Make Equal

题意:

n n n 个盛水的容器一字排开,从左到右依次编号为 1 1 1 n n n 。每个容器可以装任意数量的水;最初,第 i i i 个容器装有 a i a_i ai 个单位的水。 a i a_i ai 的和能被 n n n 整除。

你可以任意(可能是零)次地执行下面的操作:从第 i i i 个容器中倒入任意数量的水到第 j j j 个容器中,其中 i i i 必须小于 j j j (即 i < j i\lt j i<j )。任何下标都可以被选择为 i i i j j j ,次数不限。

请判断是否有可能通过这种操作使所有容器中的水量相同。

思路:

可以任意选择两个位置,并把前面的位置的容器的水向后倒任意数量的水,所以只要前面的容器水量够用,就可以倒给后面的容器,使得它们的水量相同。反之就没有办法相同。

换句话说,假设平均水量为 a v e ave ave,如果 i − 1 i-1 i1 个位置的总水量大于等于 a v e ∗ ( i − 1 ) ave*(i-1) ave(i1),那么前 i − 1 i-1 i1 个位置就可以向第 i i i 个位置贡献水量,还得有足够的水量把它变成 a v e ave ave 水量,这样 i i i 个位置的总水量大于等于 a v e ∗ i ave*i avei。否则第 i i i 个位置永远不可能达到平均水量。所以直接枚举每一个 i i i 看看它的前缀和水量是否超过了 a v e ∗ i ave*i avei,否则就会导致某个位置达不到平均水量。

code:

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=2e5+5;
typedef long long ll;int T,n,a[maxn];int main(){cin>>T;while(T--){cin>>n;ll tot=0,ave;for(int i=1;i<=n;i++){cin>>a[i];tot+=a[i];}ave=tot/n;ll res=0;bool f=true;for(int i=1;i<=n;i++){res+=a[i];if(res<ave*i){f=false;break;}}puts((f)?"YES":"NO");}return 0;
}

C. Make Equal Again

题意:

你有一个由 n n n 个整数组成的数组 a a a

您可以至多一次进行以下操作:选择三个整数 i i i , j j j , x x x ( 1 ≤ i ≤ j ≤ n 1 \le i \le j \le n 1ijn ),并将数组中索引为 i i i j j j 的所有元素赋值为 x x x 。这个操作的代价取决于所选的索引,等于 ( j − i + 1 ) (j - i + 1) (ji+1)

例如,数组等于 [ 1 , 2 , 3 , 4 , 5 , 1 ] [1, 2, 3, 4, 5, 1] [1,2,3,4,5,1] 。如果我们选择 i = 2 , j = 4 , x = 8 i = 2, j = 4, x = 8 i=2,j=4,x=8 ,那么执行此操作后,数组将等于 [ 1 , 8 , 8 , 8 , 5 , 1 ] [1, 8, 8, 8, 5, 1] [1,8,8,8,5,1]

要使数组中的所有元素相等,最少需要花费多少布尔值?

思路:

因为只能进行一次操作,还要让所有元素相同,那么就要把中间所有不同的数字全部换掉。具体来说,最左边和最右边可能有两种数字,考虑把从左边第一个不同的数字开始把后面换成最左边的数字,以及把从右边第一个不同的数字开始把前面换成最右边的数字,两种情况都算一遍然后取最小值即可。特殊情况就是左右两边数字相同,这时只换掉中间的数即可。

code:

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=2e5+5;int T,n,a[maxn];int main(){cin>>T;while(T--){cin>>n;for(int i=1;i<=n;i++)cin>>a[i];int l=1,r=n,ans=1145141919;while(l<n && a[l+1]==a[l])l++;while(r>1 && a[r-1]==a[r])r--;if(a[1]==a[n])ans=(r>l)?r-l-1:0;else ans=min(n-l,r-1);cout<<ans<<endl;}return 0;
}

D. Divisible Pairs

题意:

波利卡普有两个最喜欢的整数 x x x y y y (它们可以相等),他找到了一个长度为 n n n 的数组 a a a

如果出现以下情况,波利卡普认为一对索引 ⟨ i , j ⟩ \langle i, j \rangle i,j ( 1 ≤ i < j ≤ n 1 \le i \lt j \le n 1i<jn ) 很美:

  • a i + a j a_i + a_j ai+aj 可以被 x x x 整除;
  • a i − a j a_i - a_j aiaj 能被 y y y 整除。

例如,如果 x = 5 x=5 x=5 , y = 2 y=2 y=2 , n = 6 n=6 n=6 , a = a= a= [ 1 , 2 , 7 , 4 , 9 , 6 1, 2, 7, 4, 9, 6 1,2,7,4,9,6 ],那么唯一美丽的一对是:

  • ⟨ 1 , 5 ⟩ \langle 1, 5 \rangle 1,5 : a 1 + a 5 = 1 + 9 = 10 a_1 + a_5 = 1 + 9 = 10 a1+a5=1+9=10 10 10 10 能被 5 5 5 整除)和 a 1 − a 5 = 1 − 9 = − 8 a_1 - a_5 = 1 - 9 = -8 a1a5=19=8 ( − 8 -8 8 能被 2 2 2 整除);
  • ⟨ 4 , 6 ⟩ \langle 4, 6 \rangle 4,6 : a 4 + a 6 = 4 + 6 = 10 a_4 + a_6 = 4 + 6 = 10 a4+a6=4+6=10 10 10 10 能被 5 5 5 整除)和 a 4 − a 6 = 4 − 6 = − 2 a_4 - a_6 = 4 - 6 = -2 a4a6=46=2 ( − 2 -2 2 能被 2 2 2 整除)。

求数组 a a a 中优美对的个数。

思路:

同余的性质,相加能被x整除,那么先同余x再相加同样能被x整除,相减被y整除,那么先同余y再相减同样能被y整除(其实相当于就是两者余数相同)

所以对一个数,它同余x和同余y的余数其实已经确定了,其实就是找和它配成同余x的余数相加能被x整除以及同余y的余数相同的数前面有多少个。因为xy同样可以很大,开桶会爆空间,所以使用map或者set。

考虑使用map<pair<int,int>,int> ,前面的pair键描述分别同余x和y的余数信息,后面的int值记录数量即可。

code:

#include <iostream>
#include <cstdio>
#include <map>
using namespace std;int T,n,x,y;int main(){cin>>T;while(T--){cin>>n>>x>>y;map<pair<int,int>,int> mp;//同余x y的信息,个数 long long ans=0;for(int i=1,t;i<=n;i++){cin>>t;ans+=mp[make_pair((x-t%x)%x,t%y)];mp[make_pair(t%x,t%y)]++;}cout<<ans<<endl;}return 0;
}

E. Anna and the Valentine’s Day Gift

题意:

情人节那天,萨沙给了安娜一张 n n n 个整数的列表 a a a。安娜不需要这个列表,所以她建议通过玩游戏来销毁它。

玩家轮流玩。萨沙是个绅士,所以他让安娜先下手为强。

  • 轮到安娜时,她必须从列表中选择一个元素 a i a_i ai ,并颠倒其数字顺序。例如,如果安娜选择了数值为 42 42 42 的元素,它就会变成 24 24 24 ;如果安娜选择了数值为 1580 1580 1580 的元素,它就会变成 851 851 851 。注意,前导零会被去掉。在这一轮之后,列表中元素的数量不会改变。
  • 轮到萨沙时,他必须从列表中提取两个元素 a i a_i ai a j a_j aj ( i ≠ j i \ne j i=j ),以任意顺序将它们连接起来,并将结果插回列表。例如,如果萨沙选择了等于 2007 2007 2007 19 19 19 的元素,他将从列表中删除这两个元素,并添加整数 200719 200719 200719 192007 192007 192007 。这样转一圈后,列表中的元素数会减少 1 1 1

玩家不能跳过回合。当列表中只剩下一个整数时,游戏结束。如果这个整数不小于 1 0 m 10^m 10m (即 ≥ 1 0 m \ge 10^m 10m ),萨沙获胜。否则,安娜获胜。

由此可以看出,游戏总会结束。如果双方都以最佳方式下棋,谁会获胜?

思路:

模拟一下游玩过程很快就会发现,其实我们对这个数具体是什么根本不关心,Anna只关心能不能利用去除前导零的规则削减数位,Sasha只关心能不能利用合并规则来保护后导零不被变成前导零(要保护的数放在任意一个数前面即可)。因为 1 0 m 10^m 10m m + 1 m+1 m+1 位数中最小的那个数,所以只要你最后合并出来的数数位个数大于等于 m + 1 m+1 m+1,那么这个数就一定大于等于 1 0 m 10^m 10m,不需要关心具体合并出来一个什么东西。

模拟游玩过程,一开始Anna一定会取出当前 后导零最多的数,将它翻转,这时总的数位会损失后导零个数个数位(因为所有数都不为0,所以不用考虑0这种特殊情况)。然后Sasha会取出当前 后导零最多的数,将它保护起来,这时这个数的后导零就消失了,总位数就会累加到答案里,同理后面的步骤。

所以可以直接暴力模拟这个过程。使用set<pair<int,int> >来存储一个数,前一位表示后导零位数,后一位表示这个数的位数。每次先取出当前后导零数位个数最大的数,后导零位数归零,位数减去损失的位数,放回,然后再取出当前后导零数位个数最大的数,直接将位数加入到答案即可。不过要注意的是,数是可以重复的,后导零位数和这个数的位数是有可能重复的,但是set不能存储重复信息,所以可以多加一维,用来存储没啥特殊含义的数,用来区分它们。

code:

#include <iostream>
#include <cstdio>
#include <set>
using namespace std;int T,n,m;pair<int,int> g(int x){//后导0 总位数 int cnt1=0,cnt2;while(x%10==0){cnt1++;x/=10;}cnt2=cnt1;while(x){cnt2++;x/=10;}return make_pair(cnt1,cnt2);
}int main(){cin>>T;while(T--){cin>>n>>m;set<pair<pair<int,int>,int> > S;for(int i=1,t;i<=n;i++){cin>>t;S.insert(make_pair(g(t),i));}int ans=0;while(!S.empty()){pair<pair<int,int>,int> x=*S.rbegin();S.erase(x);x.first.second-=x.first.first;x.first.first=0;S.insert(x);x=*S.rbegin();S.erase(x);ans+=x.first.second;}puts((ans>m)?"Sasha":"Anna");}return 0;
}

其实这么写还是比较差强人意的,太麻烦了。考虑到一个数后导零被删掉之后总位数就不会再变化了,之后Anna选不选其实无所谓,Anna能消除的只有后导零位数最大的,第三大的,第五大的…所以我们记录一下总位数,然后把所有后导零位数拿出来排个序,奇数位上的后导零位数可以被Anna消除掉,就在总位数上减掉这一部分,剩下的就是答案数字的位数。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=2e5+5;int T,n,m,a[maxn];pair<int,int> g(int x){int cnt1=0,cnt2;while(x%10==0){cnt1++;x/=10;}cnt2=cnt1;while(x){cnt2++;x/=10;}return make_pair(cnt1,cnt2);
}int main(){cin>>T;while(T--){cin>>n>>m;int ans=0;for(int i=1,t;i<=n;i++){cin>>t;pair<int,int> tmp(g(t));a[i]=tmp.first;ans+=tmp.second;}sort(a+1,a+n+1,greater<int>());for(int i=1;i<=n;i+=2)ans-=a[i];puts((ans>m)?"Sasha":"Anna");}return 0;
}

F. Chat Screenshots

题意:

编程竞赛聊天室有 n n n 人。聊天参与者按活动排序,但每个人都把自己排在最前面。

例如,有 4 4 4 人参加聊天,他们的顺序是 [ 2 , 3 , 1 , 4 ] [2, 3, 1, 4] [2,3,1,4] 。那么

  • 1 1 1 个用户看到的顺序是 [ 1 , 2 , 3 , 4 ] [1, 2, 3, 4] [1,2,3,4]
  • 2 2 2 个用户看到的顺序是 [ 2 , 3 , 1 , 4 ] [2, 3, 1, 4] [2,3,1,4]
  • 3 3 3 个用户看到的顺序是 [ 3 , 2 , 1 , 4 ] [3, 2, 1, 4] [3,2,1,4]
  • 4 4 4 个用户看到的顺序是 [ 4 , 2 , 3 , 1 ] [4, 2, 3, 1] [4,2,3,1]

k k k 人在聊天中发布了截图,显示了该用户看到的参与者顺序。这些截图是在很短的时间内截取的,参与者的顺序并没有改变。

你的任务是确定所有截图是否都有一定的顺序。

思路1:

这题可以直接模拟,也可以拓扑排序,用拓扑排序很好写,甚至还看到用树状数组的。

题目上非常好心的保证了 每个截图都是一个排列,而且 k k k 个截图的开头的数字各不相同

而且手玩一下数据的话其实不难发现一般只要两组截图就可以推理出来原序列。具体来说,如果两个截图表示的原序列是一致的,那么就会出现下面这种情况(以题目第三组样例举例):
在这里插入图片描述
两个序列从 2 ∼ n 2\sim n 2n 第一个出现不同的位置 i i i 上 其中一个序列上的数一定是另一个序列的开头数字。这时这个序列第 i i i 个位置就填补上了另一个序列的漏洞,这个序列第 2 ∼ i 2\sim i 2i 和另一个序列 i ∼ n i\sim n in 组合起来就是原序列。

不过想法很美好,但是会出现特例。当这两个数在原序列中紧挨在一起时,就没有办法区分了,比如第九个样例前两个序列:

3 5 1 4 2
2 5 1 4 3

这时候可以推出来两种可行的情况:

5 1 4 3 2
5 1 4 2 3

不过也就仅此而已了,出现这种特例的原因是两者紧挨,导致另一个数被提取到前方时两者中间没有标识前后位置的数。实际上可以直接特判这种情况,然后两种情况都验证一遍。出现这种情况时,两个序列从 2 ∼ n 2\sim n 2n 第一个出现不同的位置 i i i 上 其中一个序列上的数一定是另一个序列的开头数字,反过来,另一个序列上的数也一定是这个序列的开头数字。

找到原序列后就可以对 k k k 个截图进行一一验证,前两个用来构造的截图也要验证,因为不能保证前两个截图的原序列是相同的,这时候构造出来的原序列是有问题的,不过没有关系,在验证前两个序列的时候一定会出错。

n ∗ k ≤ 2 ∗ 1 0 5 n*k\le 2*10^5 nk2105,但是 n , k ≤ 2 ∗ 1 0 5 n,k\le 2*10^5 n,k2105,所以需要动态开空间。

code1:

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn=2e5+5;int T,n,k;
int t[maxn],t1[maxn];int main(){cin>>T;while(T--){cin>>n>>k;vector<vector<int> > a(k+1,vector<int>(n+1));for(int i=1;i<=k;i++)for(int j=1;j<=n;j++)cin>>a[i][j];if(k==1){puts("YES");continue;}bool f=true,flag=false;for(int i=2;i<=n;i++){if(a[1][i]!=a[2][i]){if(a[1][i]==a[2][1]){if(a[2][i]==a[1][1]){flag=true;for(int j=2;j<=i;j++)t1[j-1]=a[2][j];for(int j=i;j<=n;j++)t1[j]=a[1][j];}for(int j=2;j<=i;j++)t[j-1]=a[1][j];for(int j=i;j<=n;j++)t[j]=a[2][j];}else if(a[2][i]==a[1][1]){for(int j=2;j<=i;j++)t[j-1]=a[2][j];for(int j=i;j<=n;j++)t[j]=a[1][j];}else {f=false;}break;}}if(!f){puts("NO");continue;}int idx;for(int i=1;i<=k;i++){idx=1;for(int j=2;j<=n;j++){if(a[i][1]==t[idx])idx++;if(a[i][j]==t[idx])idx++;else f=false;}}if(!f && flag){//打复活赛 
//			cout<<"想你了牢大"<<endl;f=true;for(int i=1;i<=k;i++){idx=1;for(int j=2;j<=n;j++){if(a[i][1]==t1[idx])idx++;if(a[i][j]==t1[idx])idx++;else f=false;}}}puts((f)?"YES":"NO");}return 0;
}

思路2:

由于每一个截图相当于确定了 2 ∼ n 2\sim n 2n 位置上的 n − 1 n-1 n1 个数的相对位置,这个相对位置是不会变化的,比如前面有个截图说2在3前面,这时如果后面有个截图说3在2前面,这时候肯定就矛盾了,所以2在3前面的事实就固定了,是一个拓扑序,所以可以使用拓扑排列。如果没法拓扑排列,说明成环了,这时就会出现矛盾。

或者换种思路,原本的顺序应该是一个从前到后的链一样的关系,所有的截图都满足这个顺序,所以应当是没有环的。如果有一个截图遵循另一个顺序,就会导致至少有一对数发生了交换,这时候从i到j的路径就会以从j到i的路径出现,也就是成环了。这个东西就可以拓扑排序来做。

code2:

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
const int maxn=2e5+5;int T,n,k;int head[maxn],d[maxn],cnt;
struct edge{int v,nxt;
}e[maxn<<1];
void add(int u,int v){d[v]++;e[++cnt].v=v;e[cnt].nxt=head[u];head[u]=cnt;
}int main(){cin>>T;while(T--){cin>>n>>k;for(int i=1;i<=n;i++)head[i]=d[i]=0;cnt=0;for(int i=1,u,v;i<=k;i++){for(int j=1;j<=n;j++){cin>>v;if(j>2)add(u,v);u=v;}}queue<int> q;int counter=0;for(int i=1;i<=n;i++)if(!d[i]){q.push(i);counter++;}while(!q.empty()){int u=q.front();q.pop();for(int i=head[u],v;i;i=e[i].nxt){v=e[i].v;d[v]--;if(!d[v]){q.push(v);counter++;}}}puts((counter==n)?"YES":"NO");}return 0;
}

思路3:

无意之间翻到的一个解法,也挺有意思的。

如果我们对第一个序列的 2 ∼ n 2\sim n 2n 上的数重新编号,其实后面的验证相当于看有没有逆序对,如果出现逆序对就错了。另外我们还要第一个序列开头数字的可能位置并进行验证,可以在验证后面的截图时看后面第一个序列开头数字的位置来找到它在第几个数和第几个数之间,如果多个截图冲突了,就说明无解。

其实树状数组实现的功能就是找逆序对。

code3:

某个大佬的解法


G. One-Dimensional Puzzle

题意:

您有一个一维拼图,所有拼图都需要排成一行,并相互连接。所有拼图元素都是完全白色的,只有当它们的形状不同时才能相互区分。

每个元素的顶部和底部都有直线边框,左右两侧都有连接点,每个连接点都可以是一个突出物或一个凹槽。不能旋转拼图。

可以看出,拼图的类型正好有 4 4 4 种。如果左边元素的右边连接点与右边元素的左边连接点相对,那么两个元素就可以连接起来。

所有可能的拼图类型。

谜题中每种类型包含 c 1 , c 2 , c 3 , c 4 c_1, c_2, c_3, c_4 c1,c2,c3,c4 个元素。如果您成功地将所有拼图组合成一条长链,那么谜题就算完成了。您想知道有多少种方法可以做到这一点。

思路:

开始之前 先讲隔板法吧。隔板法其实有两种隔板法,一种是解决 不同相同不能空盒 的组合问题,一种是解决 不同相同空盒 的组合问题(这里相同表示互不区分)。

如果我们要把 n n n 个相同的球放入到 m m m 个相同的盒子中,不能空盒,那么可以先把球一字排开, n n n 个球之间有 n − 1 n-1 n1 个空隙,我们选取其中的 m − 1 m-1 m1 个位置放入隔板,这时 m − 1 m-1 m1 个隔板就将 n n n 个球分成了 m m m 段不为空的区间,我们按顺序把每个区间的球放入盒子即可。答案就是 C n − 1 m − 1 = C n − 1 n − m C_{n-1}^{m-1}=C_{n-1}^{n-m} Cn1m1=Cn1nm

如果我们要把 n n n 个相同的球放入到 m m m 个相同的盒子中,能空盒,那么可以先留出 n + m − 1 n+m-1 n+m1 个位置,先在这 n + m − 1 n+m-1 n+m1 个位置放入 m − 1 m-1 m1 个隔板,然后把球以此放入空位置上,这时 m − 1 m-1 m1 个隔板就将 n n n 个球分成了 m m m 段可空的区间,我们按顺序把每个区间的球放入盒子即可。答案就是 C n + m − 1 m − 1 = C n + m − 1 n C_{n+m-1}^{m-1}=C_{n+m-1}^n Cn+m1m1=Cn+m1n

上面两种情形的区别只有能不能空盒,实际上,这两种问题是可以相互转化的。对n个相同球,m个不同盒,能空盒的一种合法情况中,可以给每一个盒子里放入一个球,这样问题就转化成了n+m个相同球,m个不同盒,不能空盒的一种合法情况。相反,对n个相同球,m个不同盒,不能空盒的一种合法情况中,可以给每一个盒子里拿出一个球,这样问题就转化成了n-m个相同球,m个不同盒,不能空盒的一种合法情况。这两种情况是一一映射的,方法数是相同的。如果你把 n = n + m n=n+m n=n+m 代入到不能空盒的答案 C n − 1 m − 1 C_{n-1}^{m-1} Cn1m1 中,就会得到 C n + m − 1 m − 1 C_{n+m-1}^{m-1} Cn+m1m1,正好就是下面能空盒的答案。

–分割线–

然后回到这个题,发现34号拼图是比较万金油的拼图,如果前面是突起,那么我们就可以在后面接上任意个3号拼图,最后面仍然保持突起,同理4号拼图。

那么我们先不管3和4,只看1和2,发现只能是1和2交替相接,然后1 2之间可以插入3,2 1之间可以插入4。这样的话,1和2的个数最多只能相差1。如果12个数相差为1,那么多的那个放在奇数位上,少的那个放在偶数位上。如果两者数量相同,那么谁放奇数位谁放偶数位都可以,这时有两种方案。不管怎么说,如果只有1 2的话,摆放方案都是固定的。

如果有3 4的话,3可以放在任意的1 2之间的空隙,可以放任意个,如果把1 2之间的空隙看做一个盒子,3看做球,那么就转化成了上面说的 不同盒相同球能空盒 的组合问题了,直接隔板法可以算。两头可以看做是多接了一个虚拟的1或2,这个空隙也要算。比如1 2,他可以看做是2 1 2 1,前面有个虚拟的2,后面有个虚拟的1,这样就有两个2 1空隙,一个1 2空隙。

不过相同的时候有个特殊情况,那就是 c 1 = c 2 = 0 c_1=c_2=0 c1=c2=0 的时候,这时候需要特判。

code:

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int maxn=1e6+5;int T,c1,c2,c3,c4;
ll fac[maxn<<1];ll qpow(ll a,ll b){ll base=a,ans=1;while(b){if(b&1){ans*=base;ans%=mod;}base*=base;base%=mod;b>>=1;}return ans;
}
ll inv(ll x){return qpow(x,mod-2);
}
ll C(ll a,ll b){//C_a^breturn fac[a]*inv(fac[b])%mod*inv(fac[a-b])%mod;
}int main(){fac[0]=fac[1]=1;for(int i=2;i<(maxn<<1);i++)fac[i]=fac[i-1]*i%mod;cin>>T;while(T--){cin>>c1>>c2>>c3>>c4;if(abs(c1-c2)>1){cout<<0<<endl;continue;}int a1,a2;//1 2和2 1if(abs(c1-c2)==1){a1=a2=(c1+c2+1)>>1;cout<<(C(a1+c3-1,c3)*C(a2+c4-1,c4)%mod)<<endl;}else {if(c1==0 && c2==0){if(c3 && c4){cout<<0<<endl;continue;}else {cout<<1<<endl;continue;}}a1=c1;a2=a1+1;cout<<(C(a1+c3-1,c3)*C(a2+c4-1,c4)+C(a2+c3-1,c3)*C(a1+c4-1,c4))%mod<<endl;}}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/692084.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

「WinCC报警系统专题」简述“消息系统”

WinCC通过报警给操作员提供了有关过程故障和错误的信息。它们有助于尽早检测重要情况和避免停机时间。 一、消息系统 消息&#xff08;报警&#xff09;系统由组态和运行系统组件组成。 1、组态系统 报警记录编辑器&#xff08;如图1所示&#xff09;是报警系统的组态组件。报…

docker (九)-进阶篇-docker-compos最佳实践部署zabbix

一 部署docker环境 关闭防火墙、selinux、开启docker&#xff0c;并设置开机自启动 注意点&#xff1a;docker部署的时候&#xff0c;bip要指定&#xff0c;不然会导致虚拟机ip和容器ip冲突&#xff0c;ssh连不上虚拟机 部署请参考 docker &#xff08;二&#xff09;-yum…

为什么程序员不能一次性写好,需要不停改bug?

写程序不是一次性完成的原因有很多&#xff0c;其中包括了解不充分、需求变更、复杂性、人为因素等多个方面的原因。 需求不明确&#xff1a; 在项目一开始&#xff0c;对需求可能存在歧义或不完整的理解。有时候&#xff0c;业务需求会在开发过程中发生变化&#xff0c;导致…

Go应用性能分析实战

Go很适合用来开发高性能网络应用&#xff0c;但仍然需要借助有效的工具进行性能分析&#xff0c;优化代码逻辑。本文介绍了如何通过go test benchmark和pprof进行性能分析&#xff0c;从而实现最优的代码效能。原文: Profiling Go Applications in the Right Way with Examples…

【Vuforia+Unity】AR03-圆柱体物体识别

1.创建数据库模型 这个是让我们把生活中类似圆柱体和圆锥体的物体进行AR识别所选择的模型 Bottom Diameter:底部直径 Top Diameter:顶部直径 Side Length:圆柱侧面长度 请注意&#xff0c;您不必上传所有三个部分的图片&#xff0c;但您需要先为侧面曲面关联一个图像&#…

工具分享:在线键盘测试工具

在数字化时代&#xff0c;键盘作为我们与计算机交互的重要媒介之一&#xff0c;其性能和稳定性直接影响到我们的工作效率和使用体验。为了确保键盘的每个按键都能正常工作&#xff0c;并帮助用户检测潜在的延迟、连点等问题&#xff0c;一款优质的在线键盘测试工具显得尤为重要…

Java后端底座从无到有的搭建(随笔)

文章目录 开发模式的演变草创时期1.0时期&#xff08;基座时期&#xff09;1.1时期&#xff08;低代码时期&#xff09;2.0时期&#xff08;无代码时期&#xff09; 前言&#xff1a;本文是笔者在初创公司&#xff0c;一年多来Java后端服务底座搭建过程的总结&#xff0c;如有不…

四旋翼无人机控制-零散笔记整理

四旋翼无人机控制-零散笔记整理 说明仿真框架 说明 这是低创文章&#xff0c;本意是整理本科留下来的一堆零碎的纸质笔记&#xff0c;整理完就把纸质的扔了。所以前后不连贯&#xff0c;也可能有错误&#xff0c;图片都是直接拍的笔记照片&#xff0c;很丑。如果想系统学习的可…

【C++】STL- > string类(超详解!!!)

文章目录 前言1、string类的出现1.1 C语言中的字符串1.2 平时使用 2. 标准库中的string类2.1 string类的常用文档&#xff08;重要&#xff09;&#xff01;&#xff01;&#xff01;&#xff01;2.2 string类的常用接口说明(接口原型我这里就不展示了&#xff0c;文档中都有可…

前后端分离(delivery-management)部署文档

1. 前端项目:delivery-management 1.1. 前端项目打包 执行命令:npm run build 或者yarn run build,生成dist目录。 构建流程如下图: 1.2. 文件上传 将打包好的前端项目(dist目录),上传到服务器,并拷贝到nginx安装目录html目录下。 执行上传命令(sftp):put -r E:\…

展示用HTML编写的个人简历信息

展示用HTML编写的个人简历信息 相关代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document…

Windows 自带的 Linux 子系统(WSL)安装与使用

WSL官网安装教程&#xff1a; https://learn.microsoft.com/zh-cn/windows/wsl/install Windows 自带的Linux子系统&#xff0c;比用VM什么的香太多了。可以自己看官方教程&#xff0c;也可以以下步骤完成。 如果中间遇到我没遇到的问题百度&#xff0c;可以在评论区评论&#…

Redis(03)——发布订阅

基础命令 基于频道 publish channel message&#xff1a;将信号发送到指定的频道pubsub subcommand [argument [argyment]]&#xff1a;查看订阅或发布系统状态subscribe channel [channel]&#xff1a;订阅一个或多个频道的信息unsubscribe [channel [channel]]&#xff1a;退…

Java——Stream流的学习

在开发过程中&#xff0c;经常或忽略流的使用&#xff0c;导致用的不熟练&#xff0c;于是抽时间系统的学习下stream的使用&#xff0c;找了哔哩哔哩的教程跟着看看练练。 准备工作 创建Book、Aurhor实体类&#xff0c;初始化数据 public static List<Author> getAuth…

解锁文档处理新境界:ONLYOFFICE编辑功能为开发者带来新机遇

引言 ONLYOFFICE最新发布的文档8.0版本带来了一系列引人注目的功能和优化&#xff0c;为用户提供了更强大、更高效的在线编辑体验。这次更新涵盖了多个方面&#xff0c;包括PDF表单、RTL支持、单变量求解、图表向导以及插件界面设计更新等。这些新功能不仅提升了文档处理的便利…

职业资格高级执法考试试题及答案,分享几个实用搜题和学习工具 #知识分享#微信

作为当代大学生&#xff0c;我们常常面临着繁重的学业压力和众多的学习任务。在这个信息爆炸的时代&#xff0c;如何高效地进行搜题和学习成了我们迫切需要解决的问题。幸运的是&#xff0c;随着科技的不断进步&#xff0c;我们拥有了许多方便、实用的日常搜题和学习软件。 1.…

旗舰配置,巅峰性能 | 一文玩转铁威马 『F4-424 Pro』强大的Docker虚拟机功能【附产品开箱】

旗舰配置&#xff0c;巅峰性能 | 一文玩转铁威马 『F4-424 Pro』强大的Docker&虚拟机功能【附产品开箱】 哈喽小伙伴们&#xff0c;我是Stark-C~ 开篇 记得还在两个月之前&#xff0c;我为大家介绍了国产“开箱即用”的国民专业级NAS『铁威马』&#xff1a; &#x1f53…

idea代码review工具Code Review Helper使用介绍

之前在团队里面遇到一个关于代码review的问题&#xff0c;使用gitlab自己的还是facebook的Phabricator&#xff0c;很难看到整体逻辑&#xff0c;因为业务逻辑代码可能不在这次改动范围内&#xff0c;在去源库中找不好找。针对这个刚需&#xff0c;在网上找了一个idea的代码工具…

kali安装awvs报错error creating the database

修改host文件 vim /etc/hosts 加入 127.0.0.1 kali 重启再安装即可解决

软件实例分享,操作简单美发店会员登记记账本vip会员管理系统软件教程

软件实例分享&#xff0c;操作简单美发店会员登记记账本vip会员管理系统软件教程 一、前言 以下软件程序教程以 佳易王美发店会员管理系统软件V16为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、新会员可以直接使用手.机号&#xff0c;不需…