美文网首页
2020牛客国庆集训派对题解合集

2020牛客国庆集训派对题解合集

作者: 云中翻月 | 来源:发表于2020-10-20 12:08 被阅读0次

    2020牛客国庆集训派对1

    比赛链接

    A

    题意
    给定一个长度为1e5的字符串,求从结尾开始的最长回文子串。
    题解
    逆序暴力枚举回文子串起点,用字符串Hash判断是否为回文子串。
    时间复杂度O(n)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef unsigned long long ull;
    typedef pair<int,int>pii;
    const int maxn=4e5+5;
    const int INF=0x3f3f3f3f;
    const ull p1=131ull;
    int n;
    int len;
    char s[maxn];
    ull p[maxn],h[maxn],rh[maxn];
    ull getHash(int l,int r){
        return h[r]-h[l-1]*p[r-l+1];
    }
    ull getrHash(int l,int r){
        int l1=len-r+1;
        int r1=len-l+1;
        return rh[r1]-rh[l1-1]*p[r1-l1+1];
    }
    void solve(){
        len=strlen(s+1);
        p[0]=1ull;
        h[0]=0ull;
        rep(i,1,len){
            p[i]=p[i-1]*p1;
            h[i]=h[i-1]*p1+(s[i]-'a'+1);
        }
        reverse(s+1,s+len+1);
        rep(i,1,len) rh[i]=rh[i-1]*p1+(s[i]-'a'+1);
    //  rep(i,1,len){
    //      D(h[i]);D(rh[i]);E;
    //  }
        int ans=0;
    //  rep(i,1,len/2+1){
    //      if(2*i<=len&&getHash(1,i)==getrHash(i+1,2*i)) ans=max(ans,2*i);
    //      if(2*i-1<=len&&getHash(1,i)==getrHash(i,2*i-1)) ans=max(ans,2*i-1);
    //  }
        rrep(i,len,len/2-1){
            if(2*i-len>=1&&getHash(i,len)==getrHash(2*i-len,i)) ans=max(ans,2*len-2*i+1);
            if(2*i-len-1>=1&&getHash(i,len)==getrHash(2*i-len-1,i-1)) ans=max(ans,2*len-2*i+2);
        }
        cout<<len-ans;
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("A.in","r",stdin);
        scanf("%d%s",&n,s+1);
        solve(); 
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    B

    题意
    给定一个长度为1e5的序列a,求\sum_{i=1}^{n}\sum_{j=i}^{n}gcd(a_i,...,a_j)*max(a_i,...,a_j)
    题解
    考虑每个a_i作为区间最值的贡献,则根据辗转相除法的时间复杂度,在1i中与a_i的最大公约数至多有log(i)个。
    因此可以从左到右依次将每个a_i作为区间的右端点,然后将其作为最大值的区间(这个区间可以用一个单调递减的单调栈维护)的最大值更新为a_i(这一步可以用线段树区间修改)。接下来,只要从i位置不断向前二分的找出每一段最大公约数相同的区间(静态维护区间最大公约数可以用ST实现),累计贡献即可。
    时间复杂度O(n(logn)^2)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=2e5+5;
    const int maxlogn=20;
    const int INF=0x3f3f3f3f;
    const int mod=1000000007;
    int n;
    int a[maxn];
    struct SegmentTree{
        int l,r;
        int v,tag;
    }tr[maxn<<2];
    template <typename T>
    inline void read(T &x) {
        x = 0; T f = 1; char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
        for (; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
        x *= f;
    }
    template <typename T>
    inline void w(T x) { if (x > 9) w(x / 10); putchar(x % 10 + 48); }
    template <typename T>
    inline void write(T x, char c) { if(x < 0) putchar('-'), x = -x;w(x); putchar(c); }
    inline void spread(int rt){
        if(!tr[rt].tag) return;
        tr[rt<<1].tag=tr[rt<<1|1].tag=tr[rt].tag;
        tr[rt<<1].v=1ll*tr[rt].tag*(tr[rt<<1].r-tr[rt<<1].l+1)%mod;
        tr[rt<<1|1].v=1ll*tr[rt].tag*(tr[rt<<1|1].r-tr[rt<<1|1].l+1)%mod;
        tr[rt].tag=0;
    }
    inline void pushup(int rt){
        tr[rt].v=(tr[rt<<1].v+tr[rt<<1|1].v)%mod;
    }
    void build(int rt,int l,int r){
        tr[rt].l=l,tr[rt].r=r;
        if(l==r) return;
        int mid=l+r>>1;
        build(rt<<1,l,mid),build(rt<<1|1,mid+1,r);
    }
    inline void update(int rt,int l,int r,int v){
        if(tr[rt].l>=l&&tr[rt].r<=r) {tr[rt].v=1ll*v*(tr[rt].r-tr[rt].l+1)%mod;tr[rt].tag=v;return;}
        spread(rt);
        int mid=tr[rt].l+tr[rt].r>>1;
        if(mid>=l) update(rt<<1,l,r,v);
        if(mid<r) update(rt<<1|1,l,r,v);
        pushup(rt);
    }
    inline int ask(int rt,int l,int r){
        if(tr[rt].l>=l&&tr[rt].r<=r) return tr[rt].v;
        spread(rt);
        int ans=0;
        int mid=tr[rt].l+tr[rt].r>>1;
        if(mid>=l) ans=(ans+ask(rt<<1,l,r))%mod;
        if(mid<r) ans=(ans+ask(rt<<1|1,l,r))%mod;
        return ans;
    }
    int lans[maxn],top,stk[maxn];
    int lg[maxn],f[maxn][maxlogn];
    inline int gcd(int a,int b){
        return !b?a:gcd(b,a%b);
    }
    void init(){
        top=0,lg[1]=0;
        rep(i,2,n) lg[i]=lg[i>>1]+1;
        int t=log2(n/2)+1;
        rep(i,1,n) f[i][0]=a[i];
        rep(j,1,t) rep(i,1,n-(1<<j)+1) f[i][j]=gcd(f[i][j-1],f[i+(1<<j-1)][j-1]);
        rep(i,1,n){
            while(top&&a[stk[top]]<a[i]) top--;
            lans[i]=(!top?0:stk[top])+1;
            stk[++top]=i;
        }
    }
    inline int query(int l,int r){
        int t=lg[r-l+1];
        return gcd(f[l][t],f[r-(1<<t)+1][t]);
    }
    int ans=0;
    inline void work(int x,int ups){
        if(x<=0) return;
        int l=1,r=x;
        int stdd=query(x,ups);
        while(l<r){
            int mid=l+r>>1;
    //      if(query(mid,x)==stdd) r=mid;
            if(query(mid,ups)==stdd) r=mid;
            else l=mid+1;
        }
        ans=(ans+1ll*stdd*ask(1,l,x))%mod;
        work(l-1,ups);
    }
    void solve(){
        init();
        build(1,1,n);
        rep(i,1,n){
            update(1,lans[i],i,a[i]);
            work(i,i);
        }
        write(ans,'\n');
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("B.in","r",stdin);
        read(n);
        rep(i,1,n) read(a[i]);
        solve();
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    C

    题意
    给定一棵1e5个点的树,每次可以切出一条链并接到另一个节点上。求将其转化为链的最少次数。
    题解
    结论题,统计这棵无根树所有度数大于2的节点树即可。
    时间复杂度O(n)
    代码如下

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int maxn=1e6;
    int a[maxn],n;
    long long ans;
    int main()
    {
        int x,y;
        cin>>n;
        for(int i=1;i<n;i++){
            cin>>x>>y;
            a[x]++;a[y]++;
        }
        for(int i=1;i<=n;i++){
            if(a[i]>2){
                ans+=a[i]-2;
            }
        }
        cout<<ans;
        return 0;
    }
    

    D

    题意
    在二维平面上有一条直线和1e5个点,求在这个直线上找到一个点做一个半径为R的圆,最多能覆盖多少个点。
    题解
    逆向考虑,以每个点做半径为R的圆,则每个点对应的圆,在直线上对应一段有向区间。于是题目转化为在直线上找到一个点,使得包含它的区间尽量多。
    这个问题,可以将区间左右端点的贡献分别标记为1和-1,然后将所有区间端点排序后,扫描一遍累加贡献即可。
    时间复杂度O(nlogn)
    代码如下

    #define method_2
    
    #ifdef method_1
    
    #endif
    #ifdef method_2
    /*
    100% accepted
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    const int maxn=+5;
    const int INF=0x3f3f3f3f;
    using namespace std;
    #define pii pair<double,long long>
    long long n;
    double R,A,B;
    const int N = 2e6 + 100;
    struct Node {
        double x,y;
    } a[N];
    vector<pii> v;
    bool pd(int i) {
        double l = -B,r = A;
        double clac = l * a[i].y - a[i].x * r;
        return clac < 0;
    }
    int main() {
    //  freopen("D.in","r",stdin);
        scanf("%lld%lf%lf%lf",&n,&R,&A,&B);
        for(int i = 1; i <= n; i++) {
            scanf("%lf%lf",&a[i].x,&a[i].y);
            double X = a[i].x * a[i].x + a[i].y * a[i].y;
            double Y = A * A + B * B;
            double I = (B * a[i].x - A * a[i].y) * (B * a[i].x - A * a[i].y);
            if(I - R * R * Y > 1e-8) continue;
            double len1 = ((pd(i))?-1:1)*sqrt(X - I / Y) - ((R * R - I / Y)>1e-8 ? sqrt(R * R - I / Y) : 0.0);
            double len2 = ((pd(i))?-1:1)*sqrt(X - I / Y) + ((R * R - I / Y)>1e-8 ? sqrt(R * R - I / Y) : 0.0);
            v.push_back(pii(len1,-1));
            v.push_back(pii(len2,1));
        }
        sort(v.begin(),v.end());
        int ans = 0,last = 0;
        rep0(i,0,v.size()) {
            last -= v[i].second;
            ans = max(ans,last);
        }
        cout << ans << endl;
        return 0;
    }
    #endif
    

    E

    题意
    给定l,r(l,r<=1e12),求[l,r]上所有数字的约数个数和。
    题解
    结论题,答案即为\sum_{i=1}^{r}{ \left\lfloor n/i \right \rfloor}-\sum_{i=1}^{l-1}{ \left\lfloor n/i \right \rfloor}。该式可以使用整除分块优化。
    时间复杂度O(\sqrt{n})
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=15+5;
    const int INF=0x3f3f3f3f;
    ll solve(ll n) {
        ll ans=0ll;
        for(ll l=1,r; l<=n; l=r+1) {
            r=n/(n/l);
            ans+=(r-l+1)*(n/l);
        }
        return ans;
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("E.in","r",stdin);
        ll n,m;
        cin>>n>>m;
        cout<<solve(m)-solve(n-1);
        return 0;
    }
    #endif
    #ifdef method_2
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    F

    题意
    给定1e5个数,从中找出K个,使得它们的按位与的结果最大。
    题解
    位运算的特点是每一位相互独立,于是可以考虑从最高位向最低位贪心。即每一位如果有不小于K个数字在这一位的值为1,那么这一位就可以为1。
    时间复杂度O(nlogn)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=2e5+5;
    const int maxlogn=32;
    const int INF=0x3f3f3f3f;
    int n,k,a[maxn];
    vector<int>v,tmp;
    void solve(){
        int ans=0;
        rrep(j,maxlogn-1,0){
            int cnt=0;
            tmp.clear();
            rep0(i,0,v.size()) if(v[i]&(1<<j)) cnt++,tmp.push_back(v[i]);
            if(cnt>=k){
                ans+=(1<<j);
                v.clear();
                rep0(i,0,tmp.size()) v.push_back(tmp[i]);
            }
        }
        printf("%d",ans);
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("F.in","r",stdin);
        scanf("%d%d",&n,&k);
        rep(i,1,n) scanf("%d",&a[i]),v.push_back(a[i]);
        solve();
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    G

    题意
    给定100个长度和为100的禁止字符串,要求构造一个长度为1e5的字符串不包含禁止字符串,求构造方案数。
    题解
    将所有禁止字符串插入AC自动机,于是没有被AC自动机匹配到的字符串结尾都为合法转移。所有转移方式可以构成一个矩阵,则该矩阵的n次方,即为最终存储方案数的矩阵。求矩阵的n次方可采用矩阵快速幂优化。
    时间复杂度O(100^3logn)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=5e5+5;
    const int maxm=200+5;
    const int INF=0x3f3f3f3f;
    const int mod=1000000007;
    int n,m;
    int ch[maxn][26],vis[maxn],fail[maxn],size=0;
    char S[maxn];
    struct mat{
        int s[maxm][maxm];
        void clear(){memset(s,0,sizeof(s));}
        mat operator*(const mat x)const{
            mat z;z.clear();
            rep(i,0,size) rep(j,0,size) rep(k,0,size) z.s[i][j]=(1ll*s[i][k]*x.s[k][j]%mod+z.s[i][j])%mod;
            return z;
        } 
    }ans,base;
    queue<int>q;
    void solve(){
        rep0(i,0,26) if(ch[0][i]) q.push(ch[0][i]);
        while(q.size()){
            int x=q.front();q.pop();
            rep0(i,0,26){
                int y=ch[x][i];
                if(y) fail[y]=ch[fail[x]][i],vis[y]|=vis[fail[y]],q.push(y); 
                else ch[x][i]=ch[fail[x]][i];
            } 
        }
        ans.clear();base.clear();
        rep(i,0,size) ans.s[i][i]=1;
        rep(i,0,size) rep0(j,0,26){
            if(vis[i]||vis[ch[i][j]]) continue;
            base.s[i][ch[i][j]]+=1;
    //      D(i);D(j);E;
        }
        for(;n;n>>=1,base=base*base) if(n&1) ans=ans*base;
        rep(i,1,size) ans.s[0][i]=(ans.s[0][i]+ans.s[0][i-1])%mod;
        printf("%d",ans.s[0][size]); 
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("G.in","r",stdin);
        scanf("%d%d",&n,&m);
        while(m--){
            int len,u=0;
            scanf("%d%s",&len,S);
            rep0(i,0,len){
                int c=S[i]-'a';
    //          D(c);E;
                if(!ch[u][c]) ch[u][c]=++size;
                u=ch[u][c];
            }
            vis[u]|=1;
        }
        solve();
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    const int N = 5e5 + 100,mod = 1e9 + 7;
    int ch[N][26],vis[N],fail[N],n,m,size;
    char S[N];
    struct matrix {
        int s[210][210];
        void clear() {memset(s,0,sizeof(s));}
        matrix operator *(const matrix x) const {
            matrix z;z.clear();
            for(int i = 0;i <= size;i++) {
                for(int j = 0;j <= size;j++) {
                    for(int k = 0;k <= size;k++) {
                        z.s[i][j] = (z.s[i][j] + (1LL * s[i][k] * x.s[k][j] % mod)) % mod;
                    }
                }
            }
            return z;
        }
    }ans,base;
    int main() {
        freopen("G.in","r",stdin);
        scanf("%d%d",&n,&m);
        while(m--) {
            int len,u = 0;scanf("%d%s",&len,S+1);
            for(int i = 1;i <= len;i++) {
                int c = S[i] - 'a';
                if(!ch[u][c]) ch[u][c] = ++size;
                u = ch[u][c];
            }vis[u] |= 1;
        }
        queue<int> Q;for(int i = 0;i < 26;i++) if(ch[0][i]) Q.push(ch[0][i]);
        while(!Q.empty()) {
            int u = Q.front();Q.pop();for(int i = 0;i < 26;i++) {
                int v = ch[u][i];if(v) {
                    fail[v] = ch[fail[u]][i];vis[v] |= vis[fail[v]];Q.push(v);
                }
                else ch[u][i] = ch[fail[u]][i];
            }
        }
        ans.clear();base.clear();
        for(int i = 0;i <= size;i++) ans.s[i][i] = 1;
        for(int i = 0;i <= size;i++) {
            for(int j = 0;j < 26;j++) {
                if(vis[i] || vis[ch[i][j]]) continue;
                base.s[i][ch[i][j]] += 1;
                D(i);D(j);E;
            }
        }
        for(;n;n>>=1,base = base * base) if(n&1) ans = ans * base;
        for(int i = 1;i <= size;i++) ans.s[0][i] = (ans.s[0][i] + ans.s[0][i-1]) % mod;
        cout << ans.s[0][size] << endl;
        return 0;
    }
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    H

    题意
    给定两个长度为1e5,且只含有ACTG四种字符的字符串。每次可以交换第一个字符串的两个字符,求将第一个字符串转化为第二个字符串的最小次数。
    题解
    因为字符只有四种,因此可以统计出四种字符的值。于是交换方式只有如下四种。
    a_i=b_i,不需要交换。
    a_i=b_j,a_j=b_i,需要一次交换。
    a_i=b_j,a_j=b_k,a_k=b_i,需要两次交换。
    最后一种至多需要三次交换。
    时间复杂度O(n)
    代码如下

    #include<iostream>
    #include<cstdio>
    #include<algorithm> 
    #include<cstring>
    #include<string>
    #include<vector>
    #include<map>
    using namespace std;
    int maxn=1e6+7;
    string a,b;
    map<char,int>m;
    int sum[4][4];
    
    int main(){
        cin>>a>>b;
        int len=a.size();
        m['A']=1;
        m['G']=2;
        m['T']=3;
        m['C']=0;
        int ans=0;
        for(int i=0;i<len;i++){
            if(m[a[i]]==m[b[i]]) continue;
            sum[m[a[i]]][m[b[i]]]++;
        }
        int mn;
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                mn=min(sum[i][j],sum[j][i]);
                sum[i][j]-=mn;
                sum[j][i]-=mn;
                ans+=mn;
            }
        }
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                for(int k=0;k<4;k++){
                    mn=min(sum[i][j],min(sum[j][k],sum[k][i]));
                    sum[i][j]-=mn;
                    sum[j][k]-=mn;
                    sum[k][i]-=mn;
                    ans+=mn*2;
                }
            }
        }
        for(int i=0;i<4;i++) ans+=sum[i][3]*3;
        cout<<ans;
    }
    

    I

    题意
    给定一个1e5个点的无向图,共有1e5次询问,每次给出一组点集,求该点集构成的联通块数量。数据保证所有询问点集的总点数不超过1e5。
    题解
    题解链接
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=1e5+5;
    const int S=400; //sqrt(n)
    const int INF=0x3f3f3f3f;
    int n,e,p;
    int u[maxn],v[maxn];
    int a[maxn],vis[maxn];
    vector<int>g[maxn];
    int du[maxn];
    int f[maxn];
    int find(int x){
        return f[x]==x?x:f[x]=find(f[x]);
    }
    void solve(){
        rep(i,1,e){
            if(du[u[i]]<=S) g[u[i]].push_back(v[i]);
            if(du[v[i]]<=S) g[v[i]].push_back(u[i]);
            if(du[u[i]]>S&&du[v[i]]>S) g[u[i]].push_back(v[i]),g[v[i]].push_back(u[i]);
        }
        rep(i,1,n) f[i]=i;
        while(p--){
            int k;
            scanf("%d",&k);
            rep(i,1,k) scanf("%d",&a[i]),vis[a[i]]=1;
            int ans=k;
            rep(i,1,k){
                int x=find(a[i]);
                rep0(j,0,g[a[i]].size()){       
                    int y=g[a[i]][j];
                    if(!vis[y]) continue;
    //              D(a[i]);D(y);E;
                    y=find(g[a[i]][j]);
                    if(x!=y) f[y]=x,ans--; //direct graph need add edge y->x, not x->y
                }
            }
            printf("%d\n",ans);
            rep(i,1,k) vis[a[i]]=0,f[a[i]]=a[i];
        }
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("I.in","r",stdin);
        scanf("%d%d%d",&n,&e,&p);
        rep(i,1,e) scanf("%d%d",&u[i],&v[i]),du[u[i]]++,du[v[i]]++;
        solve();
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    2020牛客国庆集训派对2

    比赛链接

    A

    题意
    给定一个1500个点的约瑟夫环,求最后一个存活的人的编号。
    题解
    刘汝佳《算法竞赛入门经典训练指南》上有关于本题的递推,不再赘述。
    时间复杂度O(n)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=1500+5;
    const int INF=0x3f3f3f3f;
    int n,m;
    int f[maxn];
    void solve(){
        memset(f,0,sizeof(f));
        f[1]=0;
        rep(i,2,n) f[i]=(f[i-1]+m)%i;
        int ans=(f[n]+1)%n;
        if(ans<=0) ans+=n;
        cout<<ans<<endl; 
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("A.in","r",stdin);
        while(cin>>n>>m){
            if(!n&&!m) break;
            solve();
        }
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    B

    题意
    给定一个1e5个点的无向图,有18条有向路径。求这些路径首尾依次连接的最短长度。
    题解
    因为只关心每条路径起点和终点,因此首先求出所有路径起点终点之间的最短路。于是剩下的18条路径是否经过的情况可以使用一个二进制数表示,继而想到使用状压DP求解。
    具体转移方程可参考哈密顿路。
    时间复杂度O(nlogn+n2^k)
    代码如下

    /*
    
    */
    #define method_2
    #ifdef method_1
    /*
    
    */
    
    #endif
    /*
    attention that 
    in long long
    INF should be 1e18
    not 0x3f3f3f3f3f3f3f3f
    this error make me sumbit for more than 20 times
    */
    #ifdef method_2
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<ll,int>pii;
    const int maxn=1e4+5;
    const int maxm=2e4+5;
    const int maxk=20;
    const ll INF=1e18;
    int n,m,k;
    int tot=1,head[maxn];
    struct node{
        int from,to;
        ll w;
    }edge[maxm];
    ll G[maxk][maxk];
    void add(int from,int to,ll w){
        edge[++tot].from=head[from],head[from]=tot,edge[tot].to=to,edge[tot].w=w;
    }
    int v[maxn];
    ll d[maxn];
    priority_queue<pii>q;
    void dijkstra(int s){
    //  memset(d,INF,sizeof(d));
        rep(i,1,n) d[i]=INF;
        memset(v,0,sizeof(v));
        while(q.size()) q.pop();
        d[s]=0ll;
        q.push(make_pair(0ll,s));
        while(q.size()){
            int x=q.top().second;q.pop();
            if(v[x]) continue;
            v[x]=1;
            for(int i=head[x];i;i=edge[i].from){
                int y=edge[i].to;ll w=edge[i].w;
                if(d[y]>d[x]+w){
                    d[y]=d[x]+w;
                    q.push(make_pair(-d[y],y));
                }
            }
        }
    }
    
    int f[maxk],t[maxk];
    ll g[maxk][1<<maxk]; 
    void dp(){
        rep(i,0,k) rep(j,0,(1<<k)) g[i][j]=INF;
        rep(i,1,k){
            g[i][1<<i-1]=G[i][i];       
    //      D(G[i][i]);E; 
        }
        /*
        rep0(j,0,1<<k){
            rep(i,1,k){
                if((j&(1<<i-1))==0) continue;
                rep(lst,1,k){
                    if(lst==i) continue;
                    if((j&(1<<lst-1))==0) continue;
                    g[i-1][j]=min(g[i-1][j],g[lst-1][j&(~(1<<i-1))]+G[i][lst]+G[i][i]);
                }
            }
        }
        */
        rep0(j,0,(1<<k)){
            rep(i,1,k){
                if((j&(1<<i-1))==0) continue;
                rep(lst,1,k){
                    if((j&(1<<lst-1))) continue;
                    g[lst][j|(1<<lst-1)]=min(g[lst][j|(1<<lst-1)],g[i][j]+G[i][lst]+G[lst][lst]);
                }
            }
        }
        ll ans=INF;
        rep(i,1,k) ans=min(ans,g[i][(1<<k)-1]);
        if(ans!=INF) printf("%lld",ans);
        else printf("-1");
    }
    void solve(){
        memset(G,INF,sizeof(G));
        rep(i,1,k){
            dijkstra(f[i]);
            rep(j,1,k) G[i][j]=d[t[j]]; 
        }
        dp();   
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("B.in","r",stdin);
        scanf("%d%d%d",&n,&m,&k);
        int from,to;
        ll w;
        rep(i,1,m) scanf("%d%d%lld",&from,&to,&w),add(from,to,w),add(to,from,w);
        rep(i,1,k) scanf("%d%d",&f[i],&t[i]);
        solve(); 
        return 0;
    }
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    C

    题意
    给定176个数字,求存在多少个极大子集,满足其中任意两个数不相邻。
    题解
    DFS模板题。
    时间复杂度O(2^{n/3})
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=+5;
    const int INF=0x3f3f3f3f;
    int f[]={0,0,0,1,3,4,5,7,9,12,16,21,28,37,49,65,86,114,151,200,265,351,465,616,816,1081,1432,1897,2513,3329,4410,5842,7739,10252,13581,17991,23833,31572,41824,55405,73396,97229,128801,170625,226030,299426,396655,525456,696081,922111,1221537,1618192,2143648,2839729,3761840,4983377,6601569,8745217,11584946,15346786,20330163,26931732,35676949,47261895,62608681,82938844,109870576,145547525,192809420,255418101,338356945,448227521,593775046,786584466,1042002567,1380359512,1828587033};
    int n;
    ll dfs(int x){
        if(x>n) return 0;
        if(x==n||x==n-1) return 1;
        ll res=0;
        res+=dfs(x+2)+dfs(x+3);
        return res;
    }
    void solve(){
        ll ans=0ll;
        ans+=dfs(1)+dfs(2);
        printf("%lld,",ans);
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("C.in","r",stdin);
    //  freopen("C.out","w",stdout);
    //  rep(i,4,76) n=i,solve();
        int kase=0;
        while(cin>>n&&n) cout<<"Case #"<<++kase<<": "<<f[n]<<endl;
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    D

    题意
    求MST。
    题解
    时间复杂度O(nlogn)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    mst模板题。 
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=100+5;
    const int INF=0x3f3f3f3f;
    int n,tot,ans,f[maxn],m;
    struct node{
        int from,to,c;
        bool operator<(const node& h)const{return c<h.c;}
    }edge[maxn*maxn];
    void add(int from,int to,int c){
        edge[++tot].from=from,edge[tot].to=to,edge[tot].c=c;
    }
    void init(){
        tot=0,ans=0;
        for(int i=1;i<=n;i++) f[i]=i;
    }
    int find(int x){
        return f[x]==x?x:f[x]=find(f[x]);
    }
    void kruskal(){
        sort(edge+1,edge+m+1);
        int cnt=0; 
        rep(i,1,m){
            if(cnt>=n-1) break;
            int x=edge[i].from,y=edge[i].to,c=edge[i].c;
            x=find(x),y=find(y);
            if(x!=y){
                f[x]=y;ans+=c;cnt++;
            }
        }
    }
    int main() {
    //  freopen("D.in","r",stdin);
        int T;
        cin>>T;
        rep(kase,1,T){
            printf("Case #%d: ",kase);
            cin>>n>>m;
            init();
            int from,to,temp;
            rep(i,1,m) cin>>from>>to>>temp,add(from,to,temp);
            kruskal();
            printf("%d meters\n",ans);
        }
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    E

    题意
    模拟矩阵乘法。
    题解
    时间复杂度O(n^3)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=20+5;
    const int INF=0x3f3f3f3f;
    int n,m,p,q;
    ll a[maxn][maxn],b[maxn][maxn],c[maxn][maxn];
    void mul(){
        rep(i,1,m) rep(j,1,q) rep(k,1,n) c[i][j]+=a[i][k]*b[k][j];
    }
    void solve(){
        memset(c,0,sizeof(c));
        if(n!=p) {printf("undefined\n");return;}
        mul();
        rep(i,1,m){
            printf("| ");
            rep(j,1,q) printf("%lld ",c[i][j]);
            printf("|\n");
        }
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("E.in","r",stdin);
        int kase=0;
        while(scanf("%d%d%d%d",&m,&n,&p,&q)==4&&m&&n&&p&&q){
            printf("Case #%d:\n",++kase);
            rep(i,1,m) rep(j,1,n) scanf("%lld",&a[i][j]);
            rep(i,1,p) rep(j,1,q) scanf("%lld",&b[i][j]);
            solve();
        }
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    F

    题意
    求下面代码的结果。n<=max \; long \; long

    sum = 0 
    for r1 = 0 to N-1     
        for c1 = 0 to N-1         
            for r2 = r1+1 to N             
                for c2 = r2+1 to N                 
                    sum = sum + (r2-r1)*(c2-c1) 
    print(sum)
    
    

    题解
    打表找规律即可。
    时间复杂度O(1)
    代码如下

    T=int(input())
    while T>0:
        T=T-1
        ans=int(1)
        n=int(input())
        ans*=int(n*(n+1)*(n+2)/6)
        ans*=ans
        print(ans)
    

    G

    题意
    模拟题。
    题解
    时间复杂度O(n)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=+5;
    const int INF=0x3f3f3f3f;
    int n;
    void solve(){
        double res=0.0;
        rep(i,1,n){
            double c,b,l,nasi;
            double sum=0.0;
            cin>>c>>b>>l>>nasi;
            sum+=c+b+l;
            res-=8.0*sum/85.0;
            res+=nasi*0.6;
            res+=0.8*c+1.0*b+1.2*l;
            res-=c*7.5/85.0+b*24.0/85.0+l*32.0/85.0; 
        }
        printf("RM%.2lf\n",res);
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("G.in","r",stdin);
        int kase=0;
        while(cin>>n&&n) cout<<"Case #"<<++kase<<": ",solve();
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    J

    题意
    求斐波那契的第n项。
    题解
    模拟即可,注意加入高精度。
    时间复杂度O(n)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=+5;
    const int INF=0x3f3f3f3f;
    const int MAXN = 550;
    const int MAXNLEN = 130;
    int F[MAXN][MAXNLEN];
    char Fi[MAXN][MAXNLEN],ans[MAXN];
    void Fibo() {
        F[1][0] = 1;
        F[2][0] = 1;
        for(int i = 3; i <= 500; ++i) {
            for(int j = 0; j <= 110; ++j) {
                F[i][j] = F[i][j] + F[i-1][j] + F[i-2][j];
                if(F[i][j] >= 10) {
                    F[i][j+1] += F[i][j]/10;
                    F[i][j] %= 10;
                }
            }
        }
        for(int i = 1; i <= 500; ++i) {
            int j;
            for(j = 110; j >= 0; j--)
                if(F[i][j] == 0)
                    continue;
                else
                    break;
            int k = 0;
            for(; j >= 0; j--)
                Fi[i][k++] = F[i][j] + '0';
            F[i][k] = '\0';
        }
    }
    void solve() {
        Fibo();
        int x; 
        while(cin>>x){
            if(x==-1) break;
            printf("Hour: %d: %s cow(s) affected\n",x,Fi[x]); 
        }
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("J.in","r",stdin);
        solve();
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    2020牛客国庆集训派对3

    比赛链接

    B

    题意
    给定一个200个点,400条边的无向图,第i条边的边权为x_i+a*y_ia[0,1]之间随机分布的常数,求起点到终点的最短路的期望。(误差小于1e-4)
    题解
    因为误差范围较小,可以将[0,1]分成1e-4份,每次求一遍最短路,累加后再除以1e-4即可。
    时间复杂度O(1e4mlogn)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<double,int>pii;
    const int maxn=200+5;
    const int maxm=400+5;
    const int INF=0x3f3f3f3f;
    int n,m,s,t; 
    double d[maxn];
    int vis[maxn];
    struct node{
        int v,x,y;
        node(){}
        node(int _v,double _x,double _y){v=_v,x=_x,y=_y;}
    };
    vector<node>g[maxn];
    priority_queue<pii>q;
    void init(){
        while(q.size()) q.pop();
        rep(i,1,n) d[i]=1e18;
        memset(vis,0,sizeof(vis)); 
    }
    double dij(double a){
        init();
        d[s]=0.0;
        q.push(make_pair(0.0,s));
        while(q.size()){
            int x=q.top().second;q.pop();
            if(vis[x]) continue;
            vis[x]=1;
            rep0(i,0,g[x].size()){
                int y=g[x][i].v;
                double w1=g[x][i].x,w2=g[x][i].y;
                if(d[y]>d[x]+w1+w2*a){
                    d[y]=d[x]+w1+w2*a;
                    q.push(make_pair(-d[y],y));
                }
            }
        }
        return d[t];
    }
    void solve(){
        int T=100000;
        double ans=0.0;
        rep(i,0,T) ans+=dij(1.0*i/T);
        printf("%.6lf",ans/(1.0*T));
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("B.in","r",stdin);
        scanf("%d%d%d%d",&n,&m,&s,&t);
        int u,v;
        double x,y;
        rep(i,1,m) scanf("%d%d%lf%lf",&u,&v,&x,&y),g[u].push_back(node(v,x,y)),g[v].push_back(node(u,x,y));
        solve();
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    D

    题意
    给定两个内切圆和1e4个位于两圆中间的点,求一个同时内切于这两个圆的圆,使得覆盖的点最多。
    题解
    两个内切圆反演后得到的是两条直线,而点的反演在两条直线之间,所求圆反演后的圆心处于这两条直线的中线上。于是可以转化为这题的做法。
    时间复杂度O(nlogn)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=1e4+5;
    const int INF=0x3f3f3f3f;
    const double eps=1e-8;
    int T;
    int n;
    double R,r;
    struct node{
        double x,y;
        node(){}
        node(double _x,double _y){x=_x,y=_y;} 
    }p[maxn];
    vector<node>v;
    inline double sqr(double x){return x*x;}
    int sgn(double x){
        if(fabs(x)<eps) return 0;
        if(x>0) return 1;
        return -1;
    }
    bool cmp(node a,node b){
        if(sgn(a.y-b.y)==0) return a.x>b.x; //1 is before -1 , considering there maybe more than two points appear at same position
        return a.y<b.y;
    }
    void init(){
        v.clear();
    }
    void solve(){
        init();
        double mid=(double)R+(double)(R*R)/(double)r;
        double rr=(double)(R*R)/(double)r-(double)R;
        rep(i,1,n){
            ll x,y;
            cin>>x>>y;
            p[i].x=(double)(4ll*R*R*x)/(double)(x*x+y*y);
            p[i].y=(double)(4ll*R*R*y)/(double)(x*x+y*y);
            //点的反演
            if(sgn(fabs(p[i].x-mid)-rr)==0){
                v.push_back(node(1.0,p[i].y));
                v.push_back(node(-1.0,p[i].y));
            }
            else if(sgn(fabs(p[i].x-mid)-rr)<0){
                double h=sqrt(sqr(rr)-sqr(p[i].x-mid));
                v.push_back(node(-1.0,p[i].y+h));
                v.push_back(node(1, p[i].y-h));
            }
            else continue;
        }
        sort(v.begin(),v.end(),cmp);    
        int ans=0,cnt=0;
        rep0(i,0,v.size()) cnt+=v[i].x,ans=max(ans,cnt);
        printf("%d\n",ans);
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("D.in","r",stdin);
        scanf("%d",&T);
        while(T--){
            scanf("%d%lf%lf",&n,&R,&r);
            solve();
        }
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    F

    题意
    求一棵无根树中度数为1的节点数。
    题解
    模拟即可。
    时间复杂度O(n)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=1e5+5;
    const int INF=0x3f3f3f3f;
    int n;
    int x,y;
    int v[maxn];
    void solve(){
        rep(i,1,n-1) scanf("%d%d",&x,&y),v[x]++,v[y]++;
        int ans=0;
        rep(i,1,n) if(v[i]==1) ans++;
        printf("%d",ans);
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("F.in","r",stdin);
        scanf("%d",&n);
        solve();
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    J

    题意
    给定一个长度为1e5的序列,每次可以选择其中m个数字,将他们全体减一。求最多能进行多少次操作。
    题解
    考虑二分答案mid,对于大于等于mid的数字,可以分配到m组里,贡献即为mid。对于小于mid的数字,则必须全部用完,贡献即为它本身。若所有数字的贡献和不小于mid*m,那么当前mid即合法。
    时间复杂度O(nlogn)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=3e5+5;
    const ll INF=0x7fffffffffffffffll;
    int n,m,T;
    ll a[maxn],sum;
    void init(){
        sum=0ll;
    }
    bool check(ll mid){
        ll res=0;
        rep(i,1,n) res+=min(a[i],mid);
        return res>=mid*m; 
    }
    void solve(){
        sort(a+1,a+n+1);
        reverse(a+1,a+n+1);
        ll l=0,r=sum/m+1;
        while(l<r){
            ll mid=l+r+1>>1;
            if(check(mid)) l=mid;
            else r=mid-1;
        }
        printf("%lld\n",l);
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("J.in","r",stdin);
        scanf("%d",&T);
        while(T--){
            init();
            scanf("%d%d",&n,&m);
            rep(i,1,n) scanf("%lld",&a[i]),sum+=a[i];
            solve();
        }
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    2020牛客国庆集训派对4

    比赛链接

    B

    题意
    求1e3个数字的最长等差子序列。
    题解
    考虑DP,设f[i,j]表示[i,j]的最长等差子序列(选取a_ia_j)。于是存在转移方程f[i,j]=max(f[k,i])+1,a_k+a_j=2*a_i。这样直接暴力枚举三个维度,时间复杂度过高。但注意到符合条件的jk是分布在i左右的,所以可以枚举i,然后用两个指针往i的两侧移动,符合条件时更新答案。
    时间复杂度O(n^2)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=5000+5;
    const int INF=0x3f3f3f3f;
    int n;
    int a[maxn],f[maxn][maxn];
    void solve(){
        sort(a+1,a+n+1);
        rep(i,1,n) rep(j,i+1,n) f[i][j]=2;
        int ans=2;
        rep(i,2,n-1){
            int k=i-1,j=i+1;
            while(k>=1&&j<=n){
                if(a[k]+a[j]<2*a[i]) j++;
                else if(a[k]+a[j]>2*a[i]) k--;
                else{
                    f[i][j]=max(f[i][j],f[k][i]+1);
                    ans=max(ans,f[i][j]);
                    k--,j++;
                }
            }
        }
        printf("%d",ans);
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("B.in","r",stdin);
        scanf("%d",&n);
        rep(i,1,n) scanf("%d",&a[i]);
        solve();
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    D

    题意
    给出两个长度为5000的 01 串a和b,求最短的 01 串 t ,使得 t 不是 a 和 b 的子序列,若有多个答案则输出字典序最小的。
    题解
    题解链接
    代码如下

    /*
    
    */
    #define method_2
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=+5;
    const int INF=0x3f3f3f3f;
    
    void solve() {
    
    }
    int main() {
    //  ios::sync_with_stdio(false);
        freopen("D.in","r",stdin);
    
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    //#pragma GCC optimize(2)
    //#pragma GCC optimize("Ofast","inline","-ffast-math")
    //#pragma GCC target("avx,sse2,sse3,sse4,mmx")
    #include<iostream>
    #include<cstdio>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<stack>
    #include<climits>
    #include<queue>
    #include<map>
    #include<set>
    #include<sstream>
    #include<cassert>
    #include<bitset>
    #include<list>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ull;
    const int inf=0x3f3f3f3f;
    const int N=4e3+100;
    char s1[N],s2[N];
    int nt1[N][2],nt2[N][2],len1,len2;
    int dp[N][N],path[N][N];
    int dfs(int x,int y) {
        if(x==len1+1&&y==len2+1)
            return dp[x][y]=0;
        if(dp[x][y]!=-1)
            return dp[x][y];
        int ans1=dfs(nt1[x][0],nt2[y][0]); // chose 0
        int ans2=dfs(nt1[x][1],nt2[y][1]); // chose 1
        if(ans1<=ans2)
            path[x][y]=0;
        else
            path[x][y]=1;
    //  D(x);D(y);D(ans1);D(ans2);E;
        return dp[x][y]=min(ans1,ans2)+1;
    }
    void print(int x,int y) {
        if(x==len1+1&&y==len2+1)
            return;
        putchar(path[x][y]+'0');
        print(nt1[x][path[x][y]],nt2[y][path[x][y]]);
    }
    void init(char s[],int &len,int nt[][2]) {
        len=strlen(s+1);
        nt[len+1][0]=nt[len+1][1]=len+1;
        nt[len][0]=nt[len][1]=len+1;
        for(int i=len-1; i>=0; i--) {
            nt[i][0]=nt[i+1][0];
            nt[i][1]=nt[i+1][1];
            nt[i][s[i+1]-'0']=i+1;
        }
    }
    
    int main() {
    //  freopen("D.in","r",stdin);
        scanf("%s%s",s1+1,s2+1);
        init(s1,len1,nt1);
        init(s2,len2,nt2);
        memset(dp,-1,sizeof(dp));
        dfs(0,0);
        print(0,0);
        return 0;
    }
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    F

    题意
    给定长度为1e5的序列,每次可以交换两个相邻元素,求将其变成合唱队形(先升序后降序)的最小次数。
    题解
    考虑每次移动当前最小的数字,那么它向左向右移动到两端的次数都可以利用树状数组确定。
    时间复杂度O(nlogn)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=100000+5;
    const int INF=0x3f3f3f3f;
    int n,a[maxn];
    int b[maxn],cnt;
    int l[maxn],r[maxn];
    int c[maxn];
    void add(int x){
        for(;x<=cnt;x+=x&-x) c[x]++;
    }
    int ask(int x){
        int res=0;
        for(;x;x-=x&-x) res+=c[x];
        return res;
    }
    void solve(){
        sort(b+1,b+n+1);
        cnt=unique(b+1,b+n+1)-b-1;
        rep(i,1,n) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
    //  rep(i,1,n) D(a[i]);
        rep(i,1,n){
            l[i]=ask(a[i]);
            add(a[i]);
        }
    //  rep(i,1,n) D(a[i]);E;
    //  rep(i,1,n) D(l[i]);E;
        memset(c,0,sizeof(c));
        rrep(i,n,1){
            r[i]=ask(a[i]);
            add(a[i]);
        }
    //  rep(i,1,n) D(r[i]);E;
        ll ans=0ll;
        rep(i,1,n){
            ans+=ll(min(i-1-l[i],n-i-r[i]));
        }
        printf("%lld",ans);
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("F.in","r",stdin);
        scanf("%d",&n);
        rep(i,1,n) scanf("%d",&a[i]),b[i]=a[i];
        solve();
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    H

    题意
    给出一棵1e5个节点的树,每个节点都有一个颜色,现在需要执行1e5次操作,每次操作分为如下两种类型:
    Q x:回答所有颜色为 x 的节点构成的连通子图含有的最少边数
    U x y:将点 x 的颜色修改为 y
    题解
    题解链接
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=1e5+5;
    const int maxlogn=20;
    const int INF=0x3f3f3f3f;
    struct node{
        int from,to;
    }edge[maxn<<1];
    int head[maxn],tot=1;
    void add(int from,int to){
        edge[++tot].from=head[from],edge[tot].to=to,head[from]=tot;
    }
    int n,m,c[maxn];
    int dfn[maxn],cnt=0;
    struct Scmp{
        bool operator()(int x,int y) {return dfn[x]<dfn[y]; }
    };
    set<int,Scmp>S[maxn];
    void dfs(int x,int fa){
        dfn[x]=++cnt;
        for(int i=head[x];i;i=edge[i].from){
            int y=edge[i].to;
            if(y==fa) continue;
            dfs(y,x);
        }
    }
    queue<int>q;
    int t;
    int d[maxn],f[maxn][maxlogn];
    void bfs(int st){
        d[st]=1;q.push(st);
        while(q.size()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=edge[i].from){
                int y=edge[i].to;
                if(d[y]) continue;
                d[y]=d[x]+1,f[y][0]=x;
                rep(j,1,t) f[y][j]=f[f[y][j-1]][j-1];
                q.push(y);
            }
        }
    //  rep(i,1,n) D(d[i]);E;
    }
    int lca(int x,int y){
        if(d[x]>d[y]) swap(x,y);
        rrep(i,t,0) if(d[f[y][i]]>=d[x]) y=f[y][i];
        if(x==y) return x;
        rrep(i,t,0) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    int dis(int x,int y){
        int res=d[x]+d[y]-2*d[lca(x,y)];
    //  D(x);D(d[x]);D(y);D(d[y]);D(lca(x,y));D(res);E;
        return res;
    }
    int ans[maxn];
    void update(int x,int flag){
        if(flag==-1) S[c[x]].erase(x);
        set<int,Scmp>::iterator it=S[c[x]].lower_bound(x),nxt,pre;
    //  D(c[x]);D(x);E;
        if(S[c[x]].empty()) ans[c[x]]=0;
        else if(it==S[c[x]].begin()||it==S[c[x]].end()){
    //      D(*S[c[x]].begin());D(*S[c[x]].rbegin());D(*it);E;
            ans[c[x]]+=flag*dis(*S[c[x]].begin(),x);
            ans[c[x]]+=flag*dis(*S[c[x]].rbegin(),x);
            ans[c[x]]-=flag*dis(*S[c[x]].begin(),*S[c[x]].rbegin());
    //      D(ans[c[x]]);E;
        } 
        else{
            nxt=it,pre=--it;
    //      D(*nxt);D(*pre);E;    
            ans[c[x]]+=flag*dis(*nxt,x);
            ans[c[x]]+=flag*dis(*pre,x);
            ans[c[x]]-=flag*dis(*pre,*nxt);
        }
        if(flag==1) S[c[x]].insert(x);
    }
    void solve(){
        char op[2];
        int x,y;
        while(m--){
            scanf("%s",op);
            if(op[0]=='Q'){
                scanf("%d",&x);
                if(S[x].empty()) printf("-1\n");
                else printf("%d\n",ans[x]/2);
            }
            if(op[0]=='U'){
                scanf("%d%d",&x,&y);
                update(x,-1);
                c[x]=y;
                update(x,1);
            }
        }
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("H.in","r",stdin);
        scanf("%d",&n);
        t=int(log(n)/log(2))+1;
        int from,to;
        rep(i,1,n-1) scanf("%d%d",&from,&to),add(from,to),add(to,from);
        dfs(1,-1);
        bfs(1);
        rep(i,1,n) scanf("%d",&c[i]),update(i,1);
        scanf("%d",&m);
        solve();
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    
    

    I

    题意
    求田忌赛马的一组字典序最大的解。(n<=5000)
    题解
    题解链接
    代码如下

    /*
    
    */
    #define method_2
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=+5;
    const int INF=0x3f3f3f3f;
    
    void solve(){
    
    }
    int main() {
    //  ios::sync_with_stdio(false);
        freopen("I.in","r",stdin);
    
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define I int
    #define ll long long
    #define F(i,a,b) for(I i=a;i<=b;++i)
    #define Fd(i,a,b) for(I i=a;i>=b;--i)
    #define mem(a,b) memset(a,b,sizeof(a))
    #define N 5010
     
    using namespace std;
    I rd(I &x){
        x=0;I w=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-') w=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        x*=w;
    }
    I n,a[N],b[N],c[N],d[N],t,s,l,r,k,mid,ans,tot;
    I cmp(I x,I y){return x>y;}
    I check(I x,I y){
        I k=0,p=0;
        F(i,1,s){
            if(k+1==x) k++;
            if(k<s&&b[k+1]>c[i]) k++,p++;
        }
        return p+tot+y==t;
    }
    I main(){
    //  freopen("I.in","r",stdin);
        scanf("%d",&n);
        F(i,1,n){scanf("%d",&a[i]),c[i]=-a[i];}
        sort(c+1,c+1+n);
        F(i,1,n) scanf("%d",&b[i]),c[i]=-c[i];
        sort(b+1,b+1+n,cmp);
        F(i,1,n) if(t<n&&b[t+1]>c[i]) t++;
        s=n+1;
        F(i,1,n-1){
            s--;
            F(j,1,s) if(c[j]==a[i]){c[j]=1e9;break;}
            I k=s+1;
            F(j,1,s) if(b[j]<=a[i]){k=j;break;}
            l=1,r=k-1,ans=0;
            while(l<=r){
                mid=(l+r)>>1;
                if(check(mid,1)){ans=mid,r=mid-1;}
                else l=mid+1;
            }
            if(!ans){
                l=k,r=s;
                while(l<=r){
                    mid=(l+r)>>1;
                    if(check(mid,0)){ans=mid,r=mid-1;}
                    else l=mid+1;
                }
            }
            printf("%d ",b[ans]);
            tot+=(b[ans]>a[i]);
            F(j,ans,s-1) b[j]=b[j+1];
            F(j,1,s) if(c[j]==1e9){
                F(k,j,s-1) c[k]=c[k+1];
                break;
            }
        }
        printf("%d ",b[1]);
        return 0;
    }
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    2020牛客国庆集训派对5

    比赛链接

    B

    题意
    给定一个长度为1e5的字符串,求它有多少个子串,重新排列后可以形成回文子串。
    题解
    一个字符串为回文串的条件是,它的所有字符中,至多只有一个字符出现次数为奇数。因此可以考虑使用异或运算维护每个字符出现次数的奇偶性。这样从左向右扫描一遍后,对于每个前缀异或值,它出现的次数即为对答案的贡献。(因为每出现一次,就意味着从上一个位置到当前位置的子串是一个合法子串)
    时间复杂度O(nlogn)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=3e5+5;
    const int maxm=52+5;
    const int INF=0x3f3f3f3f; 
    int n;
    char s[maxn];
    inline int ID(char ch){
        if(ch>='A'&&ch<='Z') return ch-'A';
        else return ch-'a'+26;
    }
    map<ll,int>mp;
    void solve(){
        ll res=0ll;
        mp.clear();
        mp[0]=1;
        ll sum=0;
        rep(i,1,n){
            int ch=ID(s[i]);
            sum^=(1ll<<ch);
            res+=ll(mp[sum]);
            rep0(j,0,52) res+=ll(mp[sum^(1ll<<j)]);
            mp[sum]++;
        }
        printf("%lld",res);
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("B.in","r",stdin);
        scanf("%d",&n);
        scanf("%s",s+1);
        solve();
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    H

    题意
    模拟题。
    题解
    时间复杂度O(n)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=1000+5;
    const int INF=0x3f3f3f3f;
    int n;
    int len;
    string s,t;
    vector<string>res;
    bool check(){
        int len2=t.length();
        if(len!=len2) return false;
        rep0(i,0,len){
            if(s[i]!='*'&&s[i]!=t[i]) return false;
        }
        return true;
    }
    void solve(){
        len=s.length();
        int cnt=0;
        res.clear();
        while(n--){
            cin>>t;
            if(check()) cnt++,res.push_back(t);
        }
        cout<<cnt<<endl;
        rep0(i,0,res.size()) cout<<res[i]<<endl; 
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("H.in","r",stdin);
        cin>>s>>n;
        solve();
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    K

    题意
    模拟题。
    题解
    时间复杂度O(n^2)
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #include<bitset>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    #define rep(i,s,t) for(int i=(s);i<=(t);i++)
    #define rep0(i,s,t) for(int i=(s);i<(t);i++)
    #define rrep(i,t,s) for(int i=(t);i>=(s);i--)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=1000+5;
    const int INF=0x3f3f3f3f;
    int n,m;
    struct node{
        int a,b;
    }c[maxn];
    int get(int i,int t){
        int times=t/(c[i].b-c[i].a);
        if(times&1) return c[i].b-t%(c[i].b-c[i].a);
        return c[i].a+t%(c[i].b-c[i].a);
    }
    void solve(){
        int x,y,t;
        while(m--){
            scanf("%d%d%d",&x,&y,&t);
            int cnt=0;
            rep(i,1,n){
                int pos=get(i,t);
    //          D(i);D(pos);E;
                if(pos>=x&&pos<=y) cnt++;
            }
            printf("%d\n",cnt);
        }
    }
    int main() {
    //  ios::sync_with_stdio(false);
    //  freopen("K.in","r",stdin);
        scanf("%d%d",&n,&m);
        rep(i,1,n) scanf("%d%d",&c[i].a,&c[i].b);
        solve();
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    相关文章

      网友评论

          本文标题:2020牛客国庆集训派对题解合集

          本文链接:https://www.haomeiwen.com/subject/irmrmktx.html