2021 CCPC 威海 A J G D(树,计算几何,组合数,字符串哈希)

 Problem - A - Codeforces

A. Goodbye, Ziyin!        【树】

题意:给出一颗无根树,询问有多少个点以它为根时是棵二 叉树。

思路:首先,只有度小于等于3的结点才能算入答案;同时,如果有结点度数为大于等于4,那么不可能为二叉树,直接输出0。

注意:快读输入,不然会超时

代码:

#include<bits/stdc++.h>
using namespace std;
vector<int> vec[1000006];
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
int main()
{
    int n;n=read();int ans=0;
    for(int i=1;i<n;i++){
        int u,v;u=read();v=read();
        vec[u].push_back(v);
        vec[v].push_back(u);
    }
    bool flag=0;
    for(int i=1;i<=n;i++){
        if(vec[i].size()>=4){flag=1;break;}
        if(vec[i].size()<3)ans++;
    }
    if(flag)cout<<0<<'\n';
    else cout<<ans<<'\n';
    return 0;
}

J. Circular Billiard Table        【计算几何 数学】

Problem - J - Codeforces

思路:从样例可以得出,目标是 180*x=a/b*y, 求的是y,y是整数,所以x最小,且使得y是整数。y=180*b*x/a,可以看出,为了使y是整数,x=a/__gcd(180b,a),所以y=180b/__gcd(180b,a)。最后输出答案y-1。

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
    int T;cin>>T;
    while(T--){
        int n,m;cin>>n>>m;
        m=180*m;
        cout<<m/__gcd(n,m)-1<<endl;
    }
}

Problem - G - Codeforces

G. Shinyruo and KFC        【组合数】

思路:目标是求出\prod_{i}^{n}\binom{m_{j}}{a_{i}},输出mj在[1,j]的所有情况

初步设想是先把所有阶乘求出来,求出 所有ai的阶乘 的乘积的逆元,然后再每一个mj的情况下,用快速幂求出m的阶乘的n次方,之后n次乘法求出(mj-ai)的阶乘。但是时间复杂度是O(mn),会超时。

优化一下,发现a的总和是1e5,所以有很多重复的a[i]值,用map存一下,最后用快速幂乘起来就可以了

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int pre[100005];
int a[50005];
map<int,int>mp;
const int mod=998244353;
long long binpow(long long a, long long b, long long m) {
  a %= m;
  long long res = 1;
  while (b > 0) {
    if (b & 1) res = (__int128)res * a % m;
    a = (__int128)a * a % m;
    b >>= 1;
  }
  return res;
}
signed main()
{
    pre[0]=1;
    int n,m;cin>>n>>m;
    for(int i=1;i<=1e5;i++){pre[i]=pre[i-1]*i%mod;}
    int maxx=0;int fb=1;
    for(int i=1;i<=n;i++){
        cin>>a[i];maxx=max(maxx,a[i]);
        fb=fb*pre[a[i]]%mod;mp[a[i]]++;
    }//分母z
    int nfb=binpow(fb,mod-2,mod);
    for(int i=1;i<=m;i++){
        if(i<maxx){cout<<0<<'\n';continue;}
        int za=binpow(pre[i],n,mod);
        int fa=1;
        //优化部分:
        for(auto v:mp){
            fa=fa*binpow(pre[i-v.first],v.second,mod);
            fa=fa%mod;
        }
        int nfa=binpow(fa,mod-2,mod);
        cout<<za*nfa%mod*nfb%mod<<'\n';
    }
    return 0;
}

Problem - D - Codeforces

D. Period

题意:给你一个字符串,q次查询,每次查询会将字符串中的一个字符修改为#,求在新串中可以选出几种长度不同的前后缀,使得前后缀相同

注意:输入取消同步,不然会超时

思路:用字符串哈希直接暴力比较前后缀是否相同

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
const unsigned long long base = 13331;
string s;int n;
unsigned long long has[N];
unsigned long long p[N];
void init(){
   p[0]=1;has[0]=0;
   n=s.size()-1;
   for(int i=1;i<=n;i++){
        p[i]=p[i-1]*base;
        has[i]=has[i-1]*base+(s[i]-'a');
   }
}
unsigned long long get(int l, int r, unsigned long long g[]){
    return g[r]-g[l-1]*p[r-l+1];
}
int ans[1000006]={0};
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin>>s;s=" "+s;init();
    int q;cin>>q;
    for(int i=1;i<=n/2;i++){
        if(get(1,i,has)==get(n-i+1,n,has)) ans[i]=ans[i-1]+1;
        else ans[i]=ans[i-1];
    }
    for(int i=1;i<=q;i++){
         int pos;cin>>pos;
         if(pos<=n/2)cout<<ans[pos-1]<<'\n';
         else {
            pos=n-pos;cout<<ans[pos]<<'\n';
         }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zy98zy998/article/details/127714653
今日推荐