2017--ccpc 杭州重现赛题解

Problem A. Super-palindrome

题意:

You are given a string that is consisted of lowercase English alphabet. You are supposed to change it into a super-palindrome string in minimum steps. You can change one character in string to another letter per step. A string is called a super-palindrome string if all its substrings with an odd length are palindrome strings. That is, for a string s, if its substring si···j satisfies j −i + 1 is odd then si+k = sj−k for k = 0,1,··· ,j −i + 1. 

Input

The first line contains an integer T (1 ≤ T ≤ 100) representing the number of test cases. For each test case, the only line contains a string, which consists of only lowercase letters. It is guaranteed that the length of string satisfies 1 ≤|s|≤ 100.

Output

For each test case, print one line with an integer refers to the minimum steps to take.

思路:签到题,

代码:

#include <bits/stdc++.h>
using namespace std;

char str[105];
int num[30];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",str);
        int len=strlen(str);

        memset(num,0,sizeof(num));
        for(int i=0;i<len;i+=2)
            num[str[i]-'a']++;
        int maxv=0;
        for(int i=0;i<26;i++)
            maxv=max(maxv,num[i]);
        int tmp=len/2;
        if(len&1) tmp++;
        tmp=tmp-maxv;
        int ans=tmp;

        memset(num,0,sizeof(num));
        for(int i=1;i<len;i+=2)
            num[str[i]-'a']++;
        maxv=0;
        for(int i=0;i<26;i++)
            maxv=max(maxv,num[i]);
        tmp=len/2;
        tmp=tmp-maxv;
        ans=ans+tmp;

        memset(num,0,sizeof(num));
        for(int i=0;i<len;i++)
            num[str[i]-'a']++;
        maxv=0;
        for(int i=0;i<26;i++)
            maxv=max(maxv,num[i]);
        tmp=len-maxv;
        ans=min(ans,tmp);
        cout<<ans<<endl;
    }
    return 0;
}

Problem B. Master of Phi

题意:

You are given an integer n. Please output the answer of∑d|n φ(d) × n d modulo 998244353. n is represented in the form of factorization. φ(n) is Euler’s totient function, and it is defined more formally as the number of integers k in the interval 1 ≤ k ≤ n for which the greatest common divisor gcd(n,k) is equal to 1. For example, the totatives of n = 9 are the six numbers 1, 2, 4, 5, 7 and 8. They are all co-prime to 9, but the other three numbers in this interval, 3, 6, and 9 are not, because gcd(9,3) = gcd(9,6) = 3 and gcd(9,9) = 9. Therefore, φ(9) = 6. As another example, φ(1) = 1 since for n = 1 the only integer in the interval from 1 to n is 1 itself, and gcd(1,1) = 1. And there are several formulas for computing φ(n), for example, Euler’s product formula states like: φ(n) = n∏p|n(1− 1 p), where the product is all the distinct prime numbers (p in the formula) dividing n.

Input 

The first line contains an integer T (1 ≤ T ≤ 20) representing the number of test cases. For each test case, the first line contains an integer m(1 ≤ m ≤ 20) is the number of prime factors. The following m lines each contains two integers pi and qi (2 ≤ pi ≤ 108, 1 ≤ qi ≤ 108) describing that n contains the factor piqi, in other words, n =∏m i=1 piqi. It is guaranteed that all pi are prime numbers and different from each other.

Output

For each test case, print the the answer modulo 998244353 in one line.

思路:数学题,对于m个素数能组成的所有因子,就是m个素数的随机组合数2^m,每个因子出现的次数=组成该因子的素因子的个数之积,带公式求值。

中间还得加一步预处理优化,不然超时、

队友推的,优秀!

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;

ll m,ans,n,a,all,j,k,p[30],q[30],tt[30];

ll fpow(ll n,ll k)//快速幂求n^k
{
    ll res=1;
    n=n%mod;
    while(k>0)
    {
        if(k&1)
            res=res*n%mod;
        n=n*n%mod;
        k>>=1;
    }
    return res;
}

void init(int m)
{
    for(int k=1;k<=m;k++)
    {
        tt[k]=q[k]*(p[k]-1)%mod*fpow(p[k],mod-2)%mod;
    }
}

void dfs(int step,ll tmp)
{
    if(step>m)
    {
        ans=(ans+n*tmp)%mod;
        return;
    }
    dfs(step+1,tmp*tt[step]%mod);
    dfs(step+1,tmp);
}

int main()
{
    int T;
   scanf("%d",&T);
   while(T--)
   {
       scanf("%lld",&m);
       n=1;
       for(int i=1;i<=m;i++)
       {
           scanf("%lld%lld",&p[i],&q[i]);
           n=n*fpow(p[i],q[i])%mod;
       }
       init(m);

       ans=0;
       dfs(1,1);

       //ans=(ans+n)%mod;
       printf("%lld\n",ans);
   }
   return 0;
}

Problem D. Master of Random

题意:

Hakase provides Nano with a problem. There is a rooted tree with values on nodes. For each query, you are asked to calculate the sum of the values in the subtree. However, Nano is a rookie so she decides to guess the answer. She has known how the data generator works: it identifies the nodes with labels from 0 to n−1 and then visits them one by one. For each i (1 ≤ i ≤ n), the generator selects a node whose label is smaller than i to be its father. The pseudocode is like this: for i = 1 to n - 1: father[i] = random(0, i - 1); where random(a, b) randomly generates a uniformly distributed random integer in range [a, b]. Knowing n and the value of the i-th node ai, Nano decides to randomly choose a subtree and sum up all of the values in the subtree as the answer. Now Hakase wants to know what the expectation of the answer is. Can you help her?

Input

The first line contains an integer T (1 ≤ T ≤ 10) representing the number of test cases. For each test case, the first line contains an integer n (1 ≤ n ≤ 100000), the number of the nodes in the rooted tree. The second line contains n integers a0,a1,...,an−1 (1 ≤ ai ≤ 100000) represent the values of nodes.

Output

It can be proven that the answer equals to an irreducible fraction p/q. For each test case, print p∗q−1 mod 998244353 in one line. q−1 is the inverse of q under module number 998244353. 

思路:首先,n个点,按照题意那么连,会有(n-1)!种树。对于每一种树,都可以对1--n点取做根。那么,所以分母就是n!

对于点1,能够加权值,只有在每棵树选点1为根的时候,所以1点的权值a[1]加了(n-1)!次

对于点2,只能够于点1连接,所以,只有在每棵树选点1为根的时候,选点2为根的时候会加其权值,所以a[2]加了2*(n-1)!次

对于点3,在每棵树选点1或点3为根的时候,加权值。有1/2的情况点三于点2相连,选点2为根的时候会加其权值。所以a[3]加了(2+1/2)*(n-1)!次.

对于点4,在每棵树选点1或点4为根的时候,加权值。有1/2的情况点4在点2的子树上,选点2为根的时候会加其权值。有1/3的情况点4在点3的子树上,选点3为根的时候会加其权值。所以a[3]加了(2+1/2+1/3)*(n-1)!次.

.。。。

画图每个都考虑考虑考虑,。就能感觉出公式来

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll MAXN=100005+100;
const ll mod=998244353;

ll n,a;
ll inv[MAXN],num[MAXN];
void init_inv()
{
    inv[1]=1;
    for(int i=2;i<MAXN;i++)
        inv[i]=(mod-mod/i)*inv[mod%i]%mod;

    num[2]=0;
    for(int i=3;i<MAXN;i++)
    {
        num[i]=(num[i-1]+inv[i-1])%mod;
    }
}

int main()
{
    init_inv();
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld",&n);
        ll ans;
        if(n>=1)
        {
            scanf("%lld",&a);
            ans=a;
        }
        if(n>=2)
        {
            scanf("%lld",&a);
        ans=(ans+a*2);
        }


        for(ll i=3;i<=n;i++)
        {
            scanf("%lld",&a);
            ans=(ans+a*(num[i]+2))%mod;
        }
        ans=ans*inv[n]%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

Problem J. Master of GCD

题意:

Hakase has n numbers in a line. At first, they are all equal to 1. Besides, Hakase is interested in primes. She will choose a continuous subsequence [l,r] and a prime parameter x each time and for every l ≤ i ≤ r, she will change ai into ai ∗x. To simplify the problem, x will be 2 or 3. After m operations, Hakase wants to know what is the greatest common divisor of all the numbers.

Input

The first line contains an integer T (1 ≤ T ≤ 10) representing the number of test cases. For each test case, the first line contains two integers n (1 ≤ n ≤ 100000) and m (1 ≤ m ≤ 100000), where n refers to the length of the whole sequence and m means there are m operations. Thefollowingmlines,eachlinecontainsthreeintegersli (1 ≤ li ≤ n), ri (1 ≤ ri ≤ n), xi (xi ∈{2,3}), which are referred above.

Output

For each test case, print an integer in one line, representing the greatest common divisor of the sequence. Due to the answer might be very large, print the answer modulo 998244353.

思路:

扫描线,线段树,都可以做。我用的扫描线,换个思路思考。因为2、3互素,所以就是考虑区间内最*2的最小次数,和*3的最小次数,之积就是所有数的GCD

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mod 998244353
struct AA
{
    int rt,num;
    bool operator<(const AA &aa)const
    {
        if(rt==aa.rt) return num>aa.num;
        return rt<aa.rt;
    }
}a[200005],b[200005];
int n,m,T,l,r,x,cnt1,cnt2,ans,anss;
ll tt;
ll POW(ll xx,int y)
{
    if(y==1) return xx;
    if(y==0) return 1;
    if(y%2==1) return POW(xx*xx%mod,y/2)*xx%mod;
    else return POW(xx*xx%mod,y/2);
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        cnt1=cnt2=0;
        ans=0x3f3f3f3f;anss=0x3f3f3f3f;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&l,&r,&x);
            if(x==2)
            {
                a[++cnt1].rt=l;
                a[cnt1].num=1;
                a[++cnt1].rt=r;
                a[cnt1].num=-1;
            }
            else
            {
                b[++cnt2].rt=l;
                b[cnt2].num=1;
                b[++cnt2].rt=r;
                b[cnt2].num=-1;
            }
        }
        sort(a+1,a+cnt1+1);
        sort(b+1,b+cnt2+1);
        x=0;
        for(int i=1;i<cnt1;i++)
        {
            x+=a[i].num;
            if(a[i].rt!=a[i+1].rt||(a[i].num==1&&a[i+1].num==-1&&a[i+1].rt==a[i].rt))
            ans=min(ans,x);
        }
        if(a[cnt1].rt!=n) ans=0;
        x=0;
        for(int i=1;i<cnt2;i++)
        {
            x+=b[i].num;
            if(b[i].rt!=b[i+1].rt||(b[i].num==1&&b[i+1].num==-1&&b[i+1].rt==b[i].rt))
            anss=min(anss,x);
        }
        if(b[cnt2].rt!=n) anss=0;
        //cout<<ans<<" "<<anss<<endl;
        tt=POW(2,ans)*POW(3,anss)%mod;
        printf("%lld\n",tt);
    }


}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值