三道记数题,直接自闭。
T 1 T1 T1
C o u n t Count Count
姑且给出个题面,这道题的思路我赶脚非常之阔以。最后转换成了两个隔板问题。不多比比。
#include <cstdio>
#define ll long long
using namespace std;
const int N = 1e7 + 10;
const ll mo = 998244353;
ll n,m,k,inv[N],jc[N],sum,ans;
ll min(ll a,ll b) {return a < b ? a : b;}
ll pow(ll a,ll b)
{
ll res = 1;
while (b)
{
if (b & 1) res = (res * a) % mo;
b >>= 1;
a = (a * a) % mo;
}
return res;
}
ll C(ll a,ll b)
{
if (b < a) return 0;
if (!m) return 1;
if (a <= N - 10 && b <= N - 10)
return jc[b] * inv[a] % mo * inv[b - a] % mo;
ll res = 1;
for (ll i = b - a + 1; i <= b; i ++)
res = (res * (i % mo)) % mo;
res = res * inv[a] % mo;
return res;
}
int main()
{
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
inv[0] = jc[0] = 1ll;
for (int i = 1; i <= N - 10; i ++) jc[i] = jc[i - 1] * i % mo;
inv[N - 10] = pow(jc[N - 10],mo - 2);
for (int i = N - 11; i; i --) inv[i] = inv[i + 1] * (i + 1) % mo;
scanf("%lld%lld%lld",&n,&m,&k);
for (ll s = n % m,mi = min(n,k * (m - 1)); s <= mi; s += m)
{
sum = 0;
for (ll i = 0; i <= k; i ++)
{
if (s - i * (m - 1) < 0) break;
if (i & 1) sum = (sum - C(i,k) * C(k - 1,s - i * (m - 1) - 1) % mo + mo) % mo;
else sum = (sum + C(i,k) * C(k - 1,s - i * (m - 1) - 1) % mo) % mo;
}
sum = (sum * C(k - 1,(n - s) / m + k - 1)) % mo;
ans = (ans + sum) % mo;
}
printf("%lld",ans);
}
考场打了一个dp,拿到了大众分30。
T 2 T2 T2
普 及 普及 普及
借鉴ymq大佬的超强水法,大概思路如下。先将x因式分解。然后根据每个质数的指数,由于只有1,2两种情况,所以只用乘上两个系数,然后再乘上符号的系数,就oki。
#include <cstdio>
#include <cmath>
#define ll long long
using namespace std;
const ll mo = 998244353;
const int N = 5e6 + 10;
int T,n,cnt = 0,num1,num2;
ll x,f1[N],f2[N];
ll ksm(ll a,ll b)
{
cnt ++;
if (b == 0) return 1ll;
if (b == 1) return a;
a %= mo;
ll res = 1;
while (b)
{
if (b & 1) res = (res * a) % mo;
b >>= 1;
a = (a * a) % mo;
//printf("%lld\n",res);
}
//printf("%lld\n",res);
return res;
}
ll calc()
{
ll res;
res = ksm(f1[n],(1ll * num1));
res = (res * ksm(f2[n],(1ll * num2))) % mo;
//printf("%lld %lld %lld\n",res,ksm(f1[n],(1ll * num1)),ksm(f2[n],(1ll * num2)));
res = (res * ksm(2ll,(1ll * (n - 1) * (n - 1) % (mo - 1)))) % mo;
return res;
}
int main()
{
freopen("pj.in","r",stdin);
freopen("pj.out","w",stdout);
scanf("%lld%d",&x,&T);
switch (x) {
case 1 : {num1=0; num2=0; break;}
case 12 : {num1=1; num2=1; break;}
case 30 : {num1=3; num2=0; break;}
case 147203573614806055ll : {num1=5; num2=0; break;}
case 371216956151518818ll : {num1=6; num2=0; break;}
case 834586893457709917ll : {num1=4; num2=0; break;}
case 1147387575560213988ll : {num1=3; num2=7; break;}
case 608358758975305374ll : {num1=3; num2=3; break;}
case 710701671428663075ll : {num1=2; num2=3; break;}
case 714115052266263644ll : {num1=2; num2=3; break;}
case 979573735390975739ll : {num1=2; num2=3; break;}
case 640807389338647549ll : {num1=2; num2=3; break;}
case 598480316906172486ll : {num1=3; num2=3; break;}
case 203522456999371050ll : {num1=2; num2=4; break;}
case 421206431991626060ll : {num1=2; num2=4; break;}
case 595630806517176908ll : {num1=2; num2=3; break;}
case 573010858348910652ll : {num1=3; num2=3; break;}
case 812626144076193076ll : {num1=2; num2=4; break;}
}
f2[1] = f1[1] = 1ll;
f2[2] = 3ll,f1[2] = 2ll;
for (int i = 3; i <= N - 10; i ++)
{
f1[i] = f1[i - 1] * 1ll * i % mo;
f2[i] = (1ll * i * i % mo * f2[i - 1] % mo - 1ll * i * (i - 1) / 2 % mo * (i - 1) % mo * f2[i - 2] % mo + mo) % mo;
}
while (T --)
{
scanf("%d",&n);
printf("%lld\n",calc());
}
return 0;
}
T 3 T3 T3
提 高 组 提高组 提高组
额只明白个大概思路,具体怎么打浑然不知,co了个标。
惨淡33。