Trig Function

来源:互联网 发布:云服务器支持java 编辑:程序博客网 时间:2024/06/05 11:56

Problem

f(cos(x))=cos(n∗x) holds for all x.
Given two integers n and m, you need to calculate the coefficient of x^m​​ in f(x), modulo 998244353.

Input Format

Multiple test cases (no more than 100).
Each test case contains one line consisting of two integers n and m.
1≤n≤10​9​,0≤m≤10​4

Output Format

Output the answer in a single line for each test case.

样例输入

2 0
2 1
2 2

样例输出

998244352
0
2

题目来源

2017 ACM-ICPC 亚洲区(西安赛区)网络赛

Solution&Code

先说题意,这是个考察第一类切比雪夫多项式的问题。对于n次多项式f(n),要求给出f(n)中次数为m的那一项的系数。

开始解题:
cos(2x) = 2cos²(x)-1.
cos(4x) = 2cos²(2x)-1 = 2(2cos²(x)-1)²-1 = 8cos(x)^4-8cos²(x)+1.
∵ sin(2x) = 2sin(x)cos(x),sin(4x) = 2sin(2x)cos(2x) = 4sin(x)cos(x)(2cos²(x)-1).
∴ cos(5x) = cos(4x)cos(x)-sin(4x)sin(x) = 8cos(x)^5-8cos³(x)+cos(x)-4sin²(x)cos(x)(2cos²(x)-1)= 8cos(x)^5-8cos³(x)+cos(x)-4(1-cos²(x))(2cos²(x)-1)cos(x)
= 16cos(x)^5-20cos³(x)+5cos(x)
……

更一般的结论:
f(0)=1;
f(1)=x;
f(n)=2x*(n-1)-f(n-2),n≥2.

e.g.
f(0)=1;
f(1)=x;
f(2)=2x2-1;
f(3)=4x3-3x;
f(4)=8x4-8x2+1;
f(5)=16x5-20x3+5x;
……

考虑到m的规模不超过1e4,n的规模不超过1e9,可以借助公式求解:
这里写图片描述
有些情况是可以特判的:
n为奇数m为偶数,或者n为偶数m为奇数,答案是0.
n为偶数m为0,当 4|n时,答案是1;否则是-1.
n为奇数m为1,答案是n.
注:维基百科的《切比雪夫多项式(Chebyshev polynomials)》链接
https://en.wikipedia.org/wiki/Chebyshev_polynomials

AC code 1(一如上述,用到了Lucas求大组合数):

#include <bits/stdc++.h>using namespace std;#define ll long longconst ll mod = 998244353ll;ll fun(ll y,ll n) {    ll s=1;    while (n) {        if (n&1) s=s*y%mod;        y=y*y%mod;        n>>=1;    }    return s;}ll Comb(ll a, ll b, ll p) {    if (a < b)   return 0;    if (a == b)  return 1;    if (b > a-b)   b = a-b;    ll ans = 1, ca = 1, cb = 1;    for (ll i = 0; i < b; ++i) {        ca = (ca * (a - i))%p;        cb = (cb * (b - i))%p;    }    ans = (ca*fun(cb, p - 2)) % p;    return ans;}ll Lucas(ll n,ll m,ll p) {    ll ans = 1;    while (n!=0&&m!=0&&ans!=0) {        ans = (ans*Comb(n%p, m%p, p)) % p;        n /= p;        m /= p;    }    return ans;}ll n,m,k,ans;int main() {    while(~scanf("%lld%lld",&n,&m)) {        if (n%2==0&&m%2!=0||n%2!=0&&m%2==0||m>n) {            printf("0\n");            continue;        }        if (m==0) {            if (n%4==0) printf("1\n");            else printf("%lld\n",mod-1);            continue;        }        k=(n-m)>>1;        ans = fun(2,n-k-k-1) * Lucas(n-k,k,mod) % mod * n % mod * fun(n-k,mod-2) % mod;        if (k&1) ans*=-1;        printf("%lld\n", (ans+mod)%mod);    }    return 0;}

AC code 2(按照队友的思路写的双阶乘)

#include <bits/stdc++.h>using namespace std;#define ll long longconst ll maxn = 20005,mod = 998244353;ll a[maxn];void init() {    ll tmp = 1;    a[0] = 1;    ll len = 20002;    for(ll i=1 ; i<=len ; i++) {        tmp = (tmp * i) % mod;        a[i] = tmp;//        cout << a[i] << endl;    }}ll fun(ll y,ll n) {    ll s=1;    while (n) {        if (n&1) s=s*y%mod;        y=y*y%mod;        n>>=1;    }    return s;}ll calc(ll x, ll y) {    ll tmp = 1;    for( ; x > y ; x -= 2) {        tmp = (tmp * x)%mod;    }    return tmp;}int main() {    init();    ll n, k;    ll tmp;    while(~scanf("%lld%lld",&n,&k)) {        if(n%2==0&&k%2!=0||n%2!=0&&k%2==0) {            printf("0\n");            continue;        }        if (k == 0) {            if (n%4==0) printf("1\n");            else printf("%lld\n",mod-1);            continue;        }        if(n&1) {            if (k&1) {                k = (k+1)>>1;                if(((n+1-2*k)>>1)&1) tmp = -1;                else tmp = 1;                ll b = calc(n+2*k-3, n+1-2*k);                tmp *= (((b * n) % mod) * fun(a[2*k-1], mod-2))%mod;            } else tmp = 0;        } else {            if (k&1) tmp = 0;            else {                k>>=1;                if(((n-2*k)>>1)&1) tmp = -1;                else tmp = 1;                ll b = calc(n+2*k-2, n-2*k);                tmp *= (((b * n) % mod) * fun(a[2*k], mod-2))%mod;            }        }        printf("%lld\n", (tmp+mod)%mod);    }    return 0;}
阅读全文
0 0