列表

详情


NC14114. Quailty's Life

描述

小Q同学最近在玩一款新出的RPG(Role-playing game)——quailty's life,其讲述的是quailty进入大学后备战ICPC Final的日常。每天他可以写一道代码题,也可以打一场比赛,还可以同时做这两件事,但是每天不做至少一件事的话他就会浑身难受然后告别ICPC生涯。
quailty定下的计划是在Final之前写够N道代码题,或者打够M场比赛,但是小Q同学发现这款游戏存在K个隐藏剧情,每个剧情有两个参数A[i],B[i](1≤ i≤ K),表示当quailty在某一天结束时总共写了恰好A[i]道代码题并且打了恰好B[i]场比赛的话就会有挂科的危险然后回去恶补文化课,从此告别ICPC生涯。
小Q同学很好奇从quailty开始备战Final到完成计划并且不经历任何挂科危险的玩法总共有多少种,由于答案太大了,你只需要给出它对P取模的值。请注意,两种玩法是相同的,当且仅当两种玩法需要的天数相同,且每天做的事情也相同。

输入描述

第一行是一个正整数T(≤ 2000),表示测试数据组数,
对于每组测试数据,
第一行是四个由空格隔开的整数N,M,K和P,1≤ N≤1000000000,1≤ M≤10000,0≤ K≤10,1≤ P<231
接下来K行,第i行是两个由空格隔开的整数A[i]和B[i],1≤ A[i]≤ N,1≤ B[i]≤ M,
保证T组数据的M之和不超过100000。

输出描述

对于每组测试数据,输出一个整数,表示答案对P取模的值。

示例1

输入:

5
1 1 0 100
1 1 1 100
1 1
3 3 2 100
1 1
2 2
10 10 0 1000000007
864852302 10000 10 1000000007
935671154 167
798739077 1373
779379402 2696
771351522 3845
601366924 4296
596084404 5458
475517977 6142
471467157 7402
124225405 8224
102396401 9382

输出:

3
2
12
8097453
499639715

说明:

对于第二组样例,满足条件的玩法只有两种,分别是在第一天写一道代码题,和在第一天打一场比赛。
对于第三组样例,不存在玩法使得quailty完成计划时恰好写了三道代码题又打了三场比赛。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 954ms, 内存消耗: 504K, 提交时间: 2022-10-07 19:52:43

#include <cstdio>
#include <algorithm>
typedef long long LL;
const int maxp = 46341, maxc = 11, maxk = 11, maxe = 51;
void exgcd(int a, int b, int &x, int &y)
{
    if(!b)
    {
        x = 1;
        y = 0;
        return;
    }
    exgcd(b, a % b, y, x);
    y -= a / b * x;
}
int mod_inv(int x, int p)
{
    int s, t;
    exgcd(x, p, s, t);
    return s < 0 ? s + p : s;
}
int tot, prime[maxp], fir[maxp], mod, cnt, fact[maxc], Exp[maxc], Coeff, Lim[maxc], Pw[maxc][maxe];
inline void mod_dec(int &x, int y, int c = 1)
{
    while(c--)
        if((x -= y) < 0)
            x += mod;
}
void init()
{
    Coeff = 1;
    for(int i = 0; i < cnt; ++i)
    {
        Exp[i] = Lim[i] = 0;
        Pw[i][0] = 1;
    }
}
void update(int val, int flag)
{
    for(int i = 0; i < cnt; ++i)
        for( ; val % fact[i] == 0; Exp[i] += flag, val /= fact[i]);
    Coeff = (LL)Coeff * (flag == 1 ? val : mod_inv(val, mod)) % mod;
}
int query()
{
    int ret = Coeff;
    for(int j = 0; j < cnt && ret; ++j)
    {
        if(!Exp[j])
            continue;
        for( ; Lim[j] < Exp[j]; ++Lim[j])
            Pw[j][Lim[j] + 1] = (LL)Pw[j][Lim[j]] * fact[j] % mod;
        ret = (LL)ret * Pw[j][Exp[j]] % mod;
    }
    return ret;
}
int calc_1(int n, int m)
{
    if(n > m)
        std::swap(n, m);
    if(n < 0)
        return 0;
    else if(!n)
        return 1;
    int ret = 0;
    init();
    for(int i = 1; i <= n; ++i)
    {
        update(m + i, 1);
        update(i, -1);
    }
    for(int i = 0; i <= n; ++i)
    {
        mod_dec(ret, mod - query());
        if(i == n)
            break;
        update(n - i, 1);
        update(m - i, 1);
        update(n + m - i, -1);
        update(i + 1, -1);
    }
    return ret;
}
int calc_2(int n, int m)
{
    if(n > m)
        std::swap(n, m);
    if(n < 0)
        return 0;
    else if(!n)
        return 1;
    int ret = 0;
    --n;
    --m;
    init();
    for(int i = 1; i <= n; ++i)
    {
        update(m + i, 1);
        update(i, -1);
    }
    update(n + m + 1, 1);
    for(int i = 0; i <= n; ++i)
    {
        update(n + 1, -1);
        mod_dec(ret, mod - query(), 2);
        update(n + 1, 1);
        update(m + 1, -1);
        mod_dec(ret, mod - query(), 2);
        update(m + 1, 1);
        update(n + m + 1 - i, -1);
        mod_dec(ret, query());
        if(i == n)
            break;
        update(n - i, 1);
        update(m - i, 1);
        update(i + 1, -1);
    }
    return ret;
}
int t, n, m, k, f[maxk], ans;
std::pair<int, int> lim[maxk];
int main()
{
    for(int i = 2; i < maxp; ++i)
    {
        if(!fir[i])
            prime[tot++] = fir[i] = i;
        for(int j = 0, k; (k = i * prime[j]) < maxp; ++j)
        {
            fir[k] = prime[j];
            if(fir[i] == prime[j])
                break;
        }
    }
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d%d%d", &n, &m, &k, &mod);
        int tmp = mod;
        cnt = 0;
        for(int i = 0; i < tot && prime[i] * prime[i] <= tmp; ++i)
            if(tmp % prime[i] == 0)
                for(fact[cnt++] = prime[i]; tmp % prime[i] == 0; tmp /= prime[i]);
        if(tmp > 1)
            fact[cnt++] = tmp;
        for(int i = 0; i < k; ++i)
            scanf("%d%d", &lim[i].first, &lim[i].second);
        std::sort(lim, lim + k);
        k = std::unique(lim, lim + k) - lim;
        for(int i = 0; i < k; ++i)
        {
            int &ai = lim[i].first, &bi = lim[i].second;
            if(ai < n && bi < m)
            {
                f[i] = calc_1(ai, bi);
                for(int j = 0; j < i; ++j)
                {
                    int &aj = lim[j].first, &bj = lim[j].second;
                    int coeff = calc_1(ai - aj, bi - bj);
                    if(coeff)
                        f[i] = (f[i] - (LL)coeff * f[j]) % mod;
                }
            }
            else
            {
                f[i] = calc_1(ai - 1, bi - 1);
                if(ai < n)
                    mod_dec(f[i], mod - calc_1(ai, bi - 1));
                if(bi < m)
                    mod_dec(f[i], mod - calc_1(ai - 1, bi));
                for(int j = 0; j < i; ++j)
                {
                    int &aj = lim[j].first, &bj = lim[j].second;
                    int coeff = calc_1(ai - 1 - aj, bi - 1 - bj);
                    if(ai < n)
                        mod_dec(coeff, mod - calc_1(ai - aj, bi - 1 - bj));
                    if(bi < m)
                        mod_dec(coeff, mod - calc_1(ai - 1 - aj, bi - bj));
                    if(coeff)
                        f[i] = (f[i] - (LL)coeff * f[j]) % mod;
                }
            }
        }
        ans = calc_2(n, m);
        for(int i = 0; i < k; ++i)
        {
            int coeff = calc_2(n - lim[i].first, m - lim[i].second);
            if(coeff)
                ans = (ans - (LL)coeff * f[i]) % mod;
        }
        if(ans < 0)
            ans += mod;
        printf("%d\n", ans);
    }
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 1131ms, 内存消耗: 720K, 提交时间: 2020-04-03 00:03:00

#include<cstdio>
#include<algorithm>
typedef long long LL;
const int maxp=46341,maxc=11,maxk=11,maxe=51;
void exgcd(int a,int b,int &x,int &y)
{
	if(!b)
	{
		x=1;
		y=0;
		return;
	}
	exgcd(b,a%b,y,x);
	y-=a/b*x;
}
int mod_inv(int x,int p)
{
	int s,t;
	exgcd(x,p,s,t);
	return s<0?s+p:s;
}
int tot,prime[maxp],fir[maxp],mod,cnt,fact[maxc],Exp[maxc],Coeff,Lim[maxc],Pw[maxc][maxe];
inline void mod_dec(int &x,int y,int c=1)
{
	while(c--)
	if((x-=y)<0)
	x+=mod;
}
void init()
{
	Coeff=1;
	for(int i=0;i<cnt;++i)
	{
		Exp[i]=Lim[i]=0;
		Pw[i][0]=1;
	}
}
void update(int val,int flag)
{
	for(int i=0;i<cnt;++i)
	for(;val%fact[i]==0;Exp[i]+=flag,val/=fact[i]);
	Coeff=(LL)Coeff*(flag==1?val:mod_inv(val,mod))%mod;
}
int query()
{
	int ret=Coeff;
	for(int j=0;j<cnt&&ret;++j)
	{
		if(!Exp[j])
		continue;
		for(;Lim[j]<Exp[j];++Lim[j])
		Pw[j][Lim[j]+1]=(LL)Pw[j][Lim[j]]*fact[j]%mod;
		ret=(LL)ret*Pw[j][Exp[j]]%mod;
	}
	return ret;
}
int calc_1(int n,int m)
{
	if(n>m)
	std::swap(n,m);
	if(n<0)
	return 0;
	else if(!n)
	return 1;
	int ret=0;
	init();
	for(int i=1;i<=n;++i)
	{
		update(m+i,1);
		update(i,-1);
	}
	for(int i=0;i<=n;++i)
	{
		mod_dec(ret,mod-query());
		if(i==n)
		break;
		update(n-i,1);
		update(m-i,1);
		update(n+m-i,-1);
		update(i+1,-1);
	}
	return ret;
}
int calc_2(int n,int m)
{
	if(n>m)
	std::swap(n,m);
	if(n<0)
	return 0;
	else if(!n)
	return 1;
	int ret=0;
	--n;
	--m;
	init();
	for(int i=1;i<=n;++i)
	{
		update(m+i,1);
		update(i,-1);
	}
	update(n+m+1,1);
	for(int i=0;i<=n;++i)
	{
		update(n+1,-1);
		mod_dec(ret,mod-query(),2);
		update(n+1,1);
		update(m+1,-1);
		mod_dec(ret,mod-query(),2);
		update(m+1,1);
		update(n+m+1-i,-1);
		mod_dec(ret,query());
		if(i==n)
		break;
		update(n-i,1);
		update(m-i,1);
		update(i+1,-1); 
	}
	return ret;
}
int t,n,m,k,f[maxk],ans;
std::pair<int,int> lim[maxk];
int main()
{
	for(int i=2;i<maxp;++i)
	{
		if(!fir[i])
		prime[tot++]=fir[i]=i;
		for(int j=0,k;(k=i*prime[j])<maxp;++j)
		{
			fir[k]=prime[j];
			if(fir[i]==prime[j])
			break;
		}
	}
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d%d%d",&n,&m,&k,&mod);
		int tmp=mod;
		cnt=0;
		for(int i=0;i<tot&&prime[i]*prime[i]<=tmp;++i)
		if(tmp%prime[i]==0)
		for(fact[cnt++]=prime[i];tmp%prime[i]==0;tmp/=prime[i]);
		if(tmp>1)
		fact[cnt++]=tmp;
		for(int i=0;i<k;++i)
		scanf("%d%d",&lim[i].first,&lim[i].second);
		std::sort(lim,lim+k);
		k=std::unique(lim,lim+k)-lim;
		for(int i=0;i<k;++i)
		{
			int &ai=lim[i].first,&bi=lim[i].second;
			if(ai<n&&bi<m)
			{
				f[i]=calc_1(ai,bi);
				for(int j=0;j<i;++j)
				{
					int &aj=lim[j].first,&bj=lim[j].second;
					int coeff=calc_1(ai-aj,bi-bj);
					if(coeff)
					f[i]=(f[i]-(LL)coeff*f[j])%mod;
				}
			}
			else
			{
				f[i]=calc_1(ai-1,bi-1);
				if(ai<n)
				mod_dec(f[i],mod-calc_1(ai,bi-1));
				if(bi<m)
				mod_dec(f[i],mod-calc_1(ai-1,bi));
				for(int j=0;j<i;++j)
				{
					int &aj=lim[j].first,&bj=lim[j].second;
					int coeff=calc_1(ai-1-aj,bi-1-bj);
					if(ai<n)
					mod_dec(coeff,mod-calc_1(ai-aj,bi-1-bj));
					if(bi<m)
					mod_dec(coeff,mod-calc_1(ai-1-aj,bi-bj));
					if(coeff)
					f[i]=(f[i]-(LL)coeff*f[j])%mod;
				}
			}
		}
		ans=calc_2(n,m);
		for(int i=0;i<k;++i)
		{
			int coeff=calc_2(n-lim[i].first,m-lim[i].second);
			if(coeff)
			ans=(ans-(LL)coeff*f[i])%mod;
		}
		if(ans<0)
		ans+=mod;
		printf("%d\n",ans); 
	}
	return 0;
}

上一题