ARC116

A-Odd vs Even
\(\quad\)因为是第一人题所以说比较简单。
\(\quad\)用小学老师交给我们的方法将一个数因数分解,这个数可以表示为多组数相乘。
\(\quad\)而我们知道

  • \(Odd * Odd = Odd\)
  • \(Odd * Even = Even\)
  • \(Even * Even = Even\)

\(\quad\)那么现在我们发现如果这个数是一个\(Odd\)那么它的所有因数都是\(Odd\)那我们就不需要思考直接输出\(Odd\)就可以了
\(\quad\)但如果这个数是\(Even\)呢?我们需要判断一下是否可能出现\(Even * Even = Even\)的情况。
\(\quad\)一个数能分为\(Even * Even\)那就说明这个数里面包含两个\(2\),所以我们就可以很轻松的解决这道题目了。
\(\quad\)关于这个数是完全平方数也是这个道理,不难证明。

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<climits>
#include<sstream>
using namespace std;
#define int long long

signed main()
{
    ios::sync_with_stdio(false);
    int t;
    cin >> t;
    for(register int i = 1 ; i <= t ; i++)
    {
        int n;
        cin >> n;
        if(n % 2 != 0)
        {
            cout << "Odd" << endl;
        }
        if(n % 2 == 0 && n % 4 != 0)
        {
            cout << "Same" << endl;
        }
        if(n % 4 == 0)
        {
            cout << "Even" << endl;
        }
    }
    return 0;
}

B-Products of Min-Max
\(\quad\)对于这种顺序无关的题目最显然的就是先排序再找性质。
\(\quad\)排完序之后我们发现如果我们使用两层循环模拟找到区间的\(Min-Max\),那么这一组答案对总答案的贡献就的次数是\(2^{p_(max)-p_(min)}-1\)
\(\quad\)如果我们考虑将所有的\(Max\)储存起来并且乘上它对答案的贡献次数,这样我们就只需要枚举\(Min\)然后让它乘上储存的数然后再把它加入这个储存并更新储存就可以了(可能有点绕)。

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<climits>
#include<sstream>
using namespace std;
#define int long long

const int N = 2e5 + 10;
const int Mod = 998244353;

int a[N];

signed main()
{
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    for(register int i = 1 ; i <= n ; i++)
    {
        cin >> a[i];
    }
    sort(a + 1 , a + n + 1);
    int count = 0;
    int ans = 0;
    for(register int i = n ; i >= 1 ; i--)
    {
        ans += a[i] * a[i];
        ans %= Mod;
        ans += a[i] * count;
        ans %= Mod;
        count *= 2;
        count += a[i];
        count %= Mod;
    }
    cout << ans;
    return 0;
}

C-Multiple Sequences
\(\quad\)我们设定好最后一个数\(A_N\),并将他质因数分解,那么得到这个\(A_N\)的过程就相当与在前的\(A_{i-1}->A_i\)过程中乘上了这个数(为了合理,我们设\(A_0=1\)
\(\quad\)此时我们会发现每一个质因数的选择是互不干扰的,并且所产生的方案数为\(C^{n+count-1}_{count}\)\(count\)为这个质因数有多少个)。
\(\quad\)既然每一个质因数是互不干扰的,那么这个指定\(A_N\)的方案数就是所以质因数的答案的乘积。
\(\quad\)显然我们只需要搜索\(O(M)\)时间枚举每一个\(A_N\)就可以得到正确的答案。

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<climits>
#include<sstream>
using namespace std;
#include<vector>
#define int long long
 
const int N = 4e5 + 10;
const int Mod = 998244353;
 
int t[N];
int p[N];
bool book[N];
int tot = 0;
 
inline void build(int n)
{
	t[0] = 1;
	for(register int i = 1 ; i <= n ; i++)
	{
		t[i] = t[i - 1] * i;
		t[i] %= Mod;
	}
	for(register int i = 2 ; i <= n ; i++)
	{
		if(book[i] == 0)
		{
			tot++;
			p[tot] = i;
		}
		else
		{
			continue;
		}
		for(register int j = i ; j <= n ; j += i)
		{
			book[j] = 1;
		}
	}
}
 
inline int pow(int a , int b , int c)
{
	int ans = 1;
	while(b)
	{
		if(b & 1)
		{
			ans *= a;
			ans %= c;
		}
		a *= a;
		a %= c;
		b >>= 1;
	}
	return ans;
}
 
inline int C(int n , int m)
{
	if(n < m)
	{
		return 0;
	}
	return (t[n] * pow((t[m] * t[n - m]) % Mod , Mod - 2 , Mod)) % Mod;
}
 
vector<int> ve;
int ans = 0;
 
int n , m;
 
inline void check(int u)
{
	int la = 0;
	int count = 0;
	int sum = 1;
	for(register int i = 0 ; i < ve.size() ; i++)
	{
		if(i == 0)
		{
			la = ve[i];
			count = 1;
			continue;
		}
		if(ve[i] != la)
		{
			sum *= C(count + n - 1 , count);
			sum %= Mod;
			la = ve[i];
			count = 1;
		}
		else
		{
			count++;
		}
	}
	sum *= C(count + n - 1 , count);
	sum %= Mod;
	ans += sum;
	ans %= Mod;
}
 
inline void dfs(int u , int la)
{
	check(u);
	for(register int i = la ; i <= tot ; i++)
	{
		int v = u * p[i];
		if(v > m)
		{
			break;
		}
		ve.push_back(p[i]);
		dfs(v , i); 
		ve.pop_back();
	}
}
 
signed main()
{
	ios::sync_with_stdio(false); 
	cin >> n >> m; 
	build(4e5);
	dfs(1 , 1);
	cout << ans;
	return 0;
}

D-I wanna Win The Game
\(\quad\)我们考虑按二进制位枚举每一个二进制为上有多少个\(1\),因为要使\(A_1 xor A_2 xor ... xor A_N = 0\),所以所有二进制位上拥有\(1\)的个数一定要是\(Even\)
\(\quad\)因为我们序列长为\(N\),所以每一个二进制位上最多只可以有\(N\)\(1\)
\(\quad\)此时我们发现每一个二进制位上的选择都是互不干扰的,所以说如果一个二进制位上选择了\(count\)\(1\),那么方案数是\(C^n_{count}\)
\(\quad\)此时我们只需要进行一个背包的DP就可以了!

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<climits>
#include<sstream>
using namespace std;
#define int long long

const int Mod = 998244353;
const int N = 5010;

int t[N];

inline int pow(int a , int b , int c)
{
    int ans = 1;
    while(b)
    {
        if(b & 1)
        {
            ans *= a;
            ans %= c;
        }
        a *= a ;
        a %= c;
        b >>= 1;
    }
    return ans;
}

inline void build()
{
    t[0] = 1;
    for(register int i = 1 ; i <= 5000 ; i++)
    {
        t[i] = t[i - 1] * i;
        t[i] %= Mod;
    }
}

inline int C(int n , int m)
{
    if(n < m)
    {
        return 0;
    }
    return (t[n] * pow((t[m] * t[n - m]) % Mod , Mod - 2 , Mod)) % Mod;
}

int f[21][N];

signed main()
{
    ios::sync_with_stdio(false);
    int n , m;
    cin >> n >> m;
    build();
    for(register int i = 0 ; i <= min(n , m) ; i += 2)
    {
        f[0][i] = C(n , i);
    }
    for(register int i = 1 ; i <= 20 ; i++)
    {
        for(register int j = m ; j >= 0 ; j--)
        {
            for(register int k = 0 ; k <= n ; k += 2)
            {
                if(j - (k * (1 << i)) < 0)
                {
                    break;
                }
                f[i][j] += (f[i - 1][j - (k * (1 << i))] * C(n , k)) % Mod;
                f[i][j] %= Mod;
            }
        }
    }
    cout << f[20][m];
    return 0;
}
posted @ 2021-07-31 18:35  玩玩就好7744  阅读(93)  评论(0编辑  收藏  举报