xj膜你赛24

昆特牌(gwent)

题目描述

作为一个资深OIer,你被邀请到位于波兰的CDPR总部参观。但没想到你刚一到就遇到了麻烦。昆特牌的数据库发生了故障。原本昆特牌中有 种卡牌和 种阵营,为了平衡,每个阵营拥有的卡牌种数都是相等的,并且每个阵营的数据顺序排列。由于故障,卡牌数据被打乱了,每个阵营现在有 种卡牌。因为昆特牌即将迎来重大更新,每种牌的所属阵营并不重要,工程师只想尽快让每个阵营拥有相同数量的卡牌。由于数据库的结构原因,你每单位时间只能将一种牌向左边或右边相邻的一个阵营移动。作为OI选手,这自然是难不倒你,但作为一名卡牌游戏爱好者,你想知道最终的卡牌分布有多少种方案。两种方案不同当且仅当存在一种卡牌,它在两种方案中所属阵营不同。对 (998244353) 取模

数据格式

输入格式

第一行一个整数 (T) ,表示数据组数。
接下来每组数据,第一行一个整数 ,第二行 (n) 个数,第 (i) 个数为 (a_i) ,意义见题目描述。

输出格式

(T) 行,每行一个数表示答案。

样例输入1

3
3
2 1 3
3
1 2 3
3
3 2 1

样例输出1

3
9
9

样例解释

对于第一组数据,初始为{{1,2}{3}{4,5,6}}
移动结束后为{{1,2}{3,4}{5,6}},{{1,2}{3,6}{4,5}},{{1,2}{3,5}{4,6}}

样例输入2

4
3
8 1 0
4
5 0 1 2
4
0 4 0 0
4
1 1 6 0

样例输出2

1120
30
24
270

数据范围

(n|k,sum_{i=1}^n a_i=k,Tle 500,nle 1000000,kle 1000)

分析

我们已知每个阵营最终拥有的牌数必定为总牌数的平均数。
我们从左往右枚举每个阵营,若阵营 (i) 牌数小于阵营 (i-1) 牌数,则牌应从 (i-1) 传到 (i) ,在节点 (i) 上打一个正数标记;否则牌应从 (i) 传到 (i-1) ,在节点 (i) 上打一个负数标记。
对于阵营间方案总数的计算,我们以如下例子分析:
设阵营1-4的传牌情况为:
1 3 2
1 <- 2 <- 3 -> 4
即从3往左穿3张牌,往右传2张牌;从2再往左传2张牌。
再设1-4的牌数为 (a_1~a_4)
那么,节点3往左和往右的总方案数为 (C(a_3,3)* C(a_3-3,2))
节点2由于收到了节点3的三张牌,自己还有 (a_2) 张,所以组合的总数为 (a_2+3) , 方案数: (C(a_2+3,1))
所以总方案数就是上述两结果的积。

Code

#include<cstdio>
#define mod 998244353
using namespace std;
typedef long long D;
inline D L(D x) { //mod
return x>=mod?x%mod:x;
}
D fac[1000002];
int a[1002],dir[1002];
D qpow(D x,D y,D p) {
	D ans=1;
	while(y) {
		if(y&1)ans=L(ans*x);
		x=L(x*x);
		y>>=1;
	}
	return ans;
}
D Div(D x,D y) {
	return L(x*qpow(y,mod-2,mod));
}
D C_(D n,D m) {
	return Div(fac[n],L(fac[m]*fac[n-m]));
}
D C(D n,D m) { //lucas
	if(!n||!m)return 1;
	return C_(L(n),L(m))*C(n/mod,m/mod);
}
int main() {
	fac[0]=1;
	for(int i=1; i<=1000001; i++)fac[i]=L(fac[i-1]*i);
	int T;
	scanf("%d",&T);
	while(T--) {
		int n,ave=0;
		scanf("%d",&n);
		for(int i=1; i<=n; i++) {
			scanf("%d",a+i);
			ave+=a[i];
		}
		ave/=n;
		int now=0;
		for(int i=1; i<=n; i++) {
			dir[i]=now;
			now+=a[i]-ave;
		}
		D ans=1;
		dir[1]=dir[n+1]=0;
		for(int i=1; i<=n; i++) {
			if(dir[i]<=0&&dir[i+1]>=0)ans=L(ans*L(C(a[i],-dir[i])*C(a[i]+dir[i],dir[i+1])));
			else if(dir[i]>=0&&dir[i+1]>=0)ans=L(ans*C(dir[i]+a[i],dir[i+1]));
			else if(dir[i]<=0&&dir[i+1]<=0)ans=L(ans*C(-dir[i+1]+a[i],-dir[i]));
		}
		printf("%lld
",ans);
	}
	return 0;
}

时空幻境(braid)

Tim拥有控制时间的能力。他学会了BFS后,出了一道题:求出一张无向图中连通块的个数。他想请你做出这道题
来。

数据格式

输入格式

第一行一个整数 (T) ,表示数据组数。
对每组数据, (n,m) 表示点数和边数。
为防止输入数据过大,边的信息以种子形式给出。输入 (x,k) ,表示 (a_1=x,a_i=a_{i-1}* k mod n) ,点从 (0) 开始标号
(i) 条边的端点为 (a_{2i-1},a{2i})

输出格式

(T) 行,每行一个数,表示联通块的个数。

样例1

输入样例1

1
998244353 4
1 3

输出样例1

998244349

样例解释

边为{1,3},{9,27},{81,243},{729,2187},所以共有 (998244349) 个联通块。

样例2

输入样例2

5
998244353 9088
709393585 591328017
998244353 8408
476368048 122172238
998244353 217
922587543 10
998244353 2948991
40846641 7
998244353 2692315
542601916 5

输出样例2

998235265
998235945
998244136
995295362
995552038

数据范围

对所有数据,(n=998244353,1le m,k,x<998244353,1le Tle 10000)

分析

(p=998244353)
由于不停地取模,所以顶点最终一定会进入一个循环。
本题是要寻找一个最小的 (a) ,使得: $$y=x* k^a$$ $$y≡x(%p)$$ a即为循环的周期。
我们已知:

费马小定理:若 (p) 为质数,且 (k,p) 互质,则 (k^{p-1}≡1(\%p))

等式两边乘以 (x)(x* k^{p-1}≡x(\%p))
所以存在一个 (y=x* k^{p-1}) ,但是,这个 (y) 不一定是最小的。所以, (a) 一定是 (998244352) 的因数。
对于 (998244352) 的所有因子 (i) ,我们用快速幂依次检验 (k^i)是否 (≡1(\%p)) ,如果可以,就跳出,说明找到了最小的 (a=i)
然后分类讨论 (a) 为奇数和偶数的情况即可。

Code

#include<cstdio>
#include<algorithm>
#define mod 998244353ll
using namespace std;
typedef long long D;
namespace W{
    D a[97]={0,1,2,4,7,8,14,16,17,28,32,34,56,64,68,112,119,128,136,224,238,256,272,448,476,512,544,896,952,
    1024,1088,1792,1904,2048,2176,3584,3808,4096,4352,7168,7616,8192,8704,14336,15232,16384,17408,28672,30464,
    32768,34816,57344,60928,65536,69632,114688,121856,131072,139264,229376,243712,262144,278528,458752,487424,
    524288,557056,917504,974848,1048576,1114112,1835008,1949696,2097152,2228224,3670016,3899392,4194304,
    4456448,7340032,7798784,8388608,8912896,14680064,15597568,17825792,29360128,31195136,35651584,58720256,
    62390272,71303168,124780544,142606336,249561088,499122176,998244352};
    const D cnt=96;
    D qpow(D x,D y){
        D ans=1;
        while(y){
            if(y&1)ans=ans*x%mod;
            x=x*x%mod;
            y>>=1;
        }
        return ans;
    }
    D work(D k){
        for(D i=1;i<=cnt;i++){
            if(qpow(k,a[i])==1)return a[i];
        }
        return 0;
    }
}
signed main(){
    D T;
    scanf("%lld",&T);
    while(T--){
        D n,m,x,k;
        scanf("%lld%lld%lld%lld",&n,&m,&x,&k);
        D w=W::work(k);
        if(w&1){
            if(m<w)printf("%lld
",n-m);
            else printf("%lld
",n-(w-1));
        }
        else{
            if(m<=(w>>1))printf("%lld
",n-m);
            else printf("%lld
",n-(w>>1));
        }
    }
    return 0;
}

初音未来(miku)

题目描述

Hercier作为一位喜爱Hatsune Miku的OIer,痛下决心,将Vocaloid买回了家。打开之后,你发现界面是一个长为 (n) 的序列,代表音调,并形成了全排列。你看不懂日语,经过多次尝试,你只会用一个按钮:将一段区间按升序排序。不理解音乐的Hercier决定写一个脚本,进行 (m) 次操作,每次对一段区间进行操作。可惜Hercier不会写脚本,他找到了在机房里的你,请你模拟出最后的结果。

数据格式

输入格式

第一行两个整数 (n,m,L,R)
接下来一行 (n) 个数,表示每个位置的音调 (a_i) 。然后 (m) 行,每行两个数 (l_i,r_i) ,表示操作的区间为 ([l_i,r_i])

输出格式

一行 (R-L+1) 个数,表示最终序列的 (a_L...a_R)

样例1

输入数据

5 2 1 5
5 1 4 2 3
1 3
2 4

输出数据

1 2 4 5 3

样例解释

[514]23 -> [145]23
1[452]3 -> 1[245]3

数据范围

(nle 1500,mle 1000000)

分析

对一个序列排序,最少的交换次数为这个序列的逆序对个数,具体操作方法为交换逆序对。
我们先随便用一个数据结构(set)来存储相邻逆序对,若 (a[i]>a[i+1]) ,则把 (i) 插入set。
然后模拟冒泡排序,对于每一个需要排序的区间,我们二分查找到第一个 (ge l) 的位置 (i) ,然后 (swap(a[i],a[i+1])) 消去一个逆序对,并且检查是否有新逆序对产生,如果有,再加入set,继续二分查找,直到找不到为止。

Code

#include<cstdio>
#include<set>
#define maxn 1505 
using namespace std;
int a[maxn];
set<int> st;
void bubblesort(int l,int r){
    set<int>::iterator t;
    int p;
    while(1){
        t=st.lower_bound(l);
        if(t==st.end()||*t>=r)break;
        p=*t;
        swap(a[p],a[p+1]);
        st.erase(t);
        if(a[p-1]>a[p])st.insert(p-1);
        if(a[p+1]>a[p+2])st.insert(p+1);
    }
}
int main(){
    int n,m,l,r;
    scanf("%d%d%d%d",&n,&m,&l,&r);
    for(int i=1;i<=n;i++){
        scanf("%d",a+i);
        if(i!=1&&a[i-1]>a[i])st.insert(i-1);
    }
    while(m--){
        int x,y;
        scanf("%d%d",&x,&y);
        bubblesort(x,y);
    }
    for(int i=l;i<=r;i++)printf("%d ",a[i]);
    return 0;
} 
原文地址:https://www.cnblogs.com/BlogOfchc1234567890/p/9897220.html