2019 ICPC中国邀请赛(南昌)暨国际丝绸之路程序设计竞赛-网络赛题解

以下所有AC题解程序来自“仙客传奇”团队。

A. PERFECT NUMBER PROBLEM

解题思路:先编写离线程序计算出最小的5个完美数,用那5个数编写解题程序。

计算最小完美数的离线程序:I00035 完美数(Perfect number)

暴力法是搞不定的。以下的暴力计算完美数程序,运行了一个多小时,只出四个数:
在这里插入图片描述

AC的C++语言程序如下:

#include <stdio.h>

int ans[] = {6, 28, 496, 8128, 33550336};
const int N = sizeof(ans) / sizeof(int);

int main()
{
    for(int i = 0; i < N; i++)
        printf("%d\n", ans[i]);
        
    return 0;
}

最简洁的代码,AC的C语言程序如下:

#include <stdio.h>
int main(){puts("6\n28\n496\n8128\n33550336\n"); return 0;}

比赛官方题解代码(C语言):

#include <stdio.h>
int main(){
	int x[5] = {1, 2, 4, 6, 12};
	int i;
	for(i = 0; i < 5; i++) {
		printf("%d\n", (1 << x[i]) * ((1 << x[i] + 1) - 1));
	}
	return 0;
}



B. Greedy HOUHOU

题解链接:【2019南昌邀请赛网络赛 B Greedy HOUHOU & BZOJ 2957 楼房重建】线段树+二分



C. Angry FFF Party
AC的Java语言程序:

import java.util.Scanner;
import java.math.BigInteger;
import java.util.ArrayList;

/**
 * 解决问题的核心类,使用矩阵快速幂来计算斐波那契数列的某一项,
 * 由于题目数列是F(F(x)),可以发现这个数列增长非常快,
 * 因为数值很大,使用Java的BigInteger类存放。
 * 对于<=10的部分,因为要求字典序最小解,因此需要特判。
 * 对于>10的部分,可以发现分解方式唯一,直接倒着贪心减去打表内的数据就好了。
 */
public class Main {
    // LIM表示打表的大小,根据输入数据的大小调整这个值来打不同范围的表
    private static int LIM = 30;
    // ZERO、ONE、TWO都是预定义的BigInteger类实例,用来表示数值0、1、2
    private static final BigInteger ZERO = BigInteger.valueOf(0);
    private static final BigInteger ONE = BigInteger.valueOf(1);
    private static final BigInteger TWO = BigInteger.valueOf(2);
    // 存放打好的表,table[i]将等于F(F(i))的函数值
    private static BigInteger[] table;

    /**
     * 解决问题的主方法
     */
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        build(LIM);
        int t;
        t = in.nextInt();
        for (int k = 0; k < t; k++) {
            BigInteger W;
            W = in.nextBigInteger();
            ArrayList<Integer> ans = new ArrayList<Integer>();
            for (int i = table.length - 1; i > 5; i--) {
                if (W.compareTo(table[i]) >= 0) {
                    W = W.subtract(table[i]);
                    ans.add(i);
                }
            }
            boolean flag = false;
            if (W.compareTo(ZERO) != 0) {
                if (W.compareTo(BigInteger.valueOf(10)) <= 0) {
                    if (W.compareTo(BigInteger.valueOf(1)) == 0)
                        System.out.print("1");
                    else if (W.compareTo(BigInteger.valueOf(2)) == 0)
                        System.out.print("1 2");
                    else if (W.compareTo(BigInteger.valueOf(3)) == 0)
                        System.out.print("1 2 3");
                    else if (W.compareTo(BigInteger.valueOf(4)) == 0)
                        System.out.print("1 2 4");
                    else if (W.compareTo(BigInteger.valueOf(5)) == 0)
                        System.out.print("1 2 3 4");
                    else if (W.compareTo(BigInteger.valueOf(6)) == 0)
                        System.out.print("1 5");
                    else if (W.compareTo(BigInteger.valueOf(7)) == 0)
                        System.out.print("1 2 5");
                    else if (W.compareTo(BigInteger.valueOf(8)) == 0)
                        System.out.print("1 2 3 5");
                    else if (W.compareTo(BigInteger.valueOf(9)) == 0)
                        System.out.print("1 2 4 5");
                    else
                        System.out.print("1 2 3 4 5");
                    flag = true;
                } else {
                    System.out.println("-1");
                    continue;
                }
            }
            for (int i = ans.size() - 1; i >= 0; i--) {
                if (flag) System.out.print(" ");
                flag = true;
                System.out.print(ans.get(i));
            }
            System.out.println();
        }
    }

    /**
     * 用来进行打表操作的接口函数
     * @param x 打表的大小
     */
    private static void build(int x) {
        table = new BigInteger[x + 1];
        for (int i = 1; i <= x; i++)
            table[i] = buildUtil(i);
    }

    /**
     * 用来打表的实用函数,即计算某一项的函数
     * @param x 所要计算的项数
     * @return F(F(x))的值
     */
    private static BigInteger buildUtil(int x) {
        Matrix base = new Matrix();
        base.d[0][0] = BigInteger.valueOf(1);
        base.d[0][1] = BigInteger.valueOf(1);
        base.d[1][0] = BigInteger.valueOf(1);
        BigInteger tmp = fp(base, BigInteger.valueOf(x));
        base = new Matrix();
        base.d[0][0] = BigInteger.valueOf(1);
        base.d[0][1] = BigInteger.valueOf(1);
        base.d[1][0] = BigInteger.valueOf(1);
        tmp = fp(base, tmp);
        return tmp;
    }

    /**
     * 矩阵快速幂,用来计算斐波那契数列的某一项
     * @param b 底数
     * @param p 指数
     * @return 斐波那契数列的第p项,即F(p)
     */
    private static BigInteger fp(Matrix b, BigInteger p) {
        Matrix ret = new Matrix();
        ret.d[0][0] = BigInteger.valueOf(1);
        do {
            if (p.remainder(TWO).compareTo(ONE) == 0) ret = b.mul(ret);
            b = b.mul(b);
            p = p.divide(TWO);
        } while (p.compareTo(ZERO) > 0);
        return ret.d[1][0];
    }

}

/**
 * 矩阵类,定义了矩阵的规模以及乘法运算
 */
class Matrix {
    public BigInteger[][] d;
    public Matrix() {
        d = new BigInteger[2][2];
        for (int i = 0; i < 2; i++)
            for (int j = 0; j < 2; j++)
                d[i][j] = BigInteger.valueOf(0);
    }
    public Matrix mul(Matrix m) {
        Matrix ret = new Matrix();
        for (int i = 0; i < 2; i++)
            for (int k = 0; k < 2; k++)
                // 左矩阵的d[i][k]位置上为0时不用计算,以此减少稀疏矩阵的计算量
                if (d[i][k].compareTo(BigInteger.valueOf(0)) != 0)
                    for (int j = 0; j < 2; j++)
                        ret.d[i][j] = ret.d[i][j].add(d[i][k].multiply(m.d[k][j]));
        return ret;
    }
}



D. Match Stick Game

AC的C++语言程序:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<ctime>
#include<ctype.h>
#include<stdlib.h>
#include<bitset>
#include<algorithm>
#include<assert.h>
#include<numeric> //accumulate
#define endl "\n"
#define fi first
#define se second
#define FOR(i,s,t) for(int i=(s);i<=(t);++i)
#define mem(a,b) memset(a,b,sizeof(a))
#define rush() int MYTESENUM;scanf("%d",&MYTESENUM);while(MYTESENUM--)
#define debug(x) printf("%d\n",x)
using namespace std;
const int maxn=700+5;
const int c[]={6,2,5,5,4,5,6,3,7,6};
long long f[maxn][maxn][2];
int wi[100+5];
int n;
char expr[100+5];
inline long long power(int x)
{
    return x==0?1:10*power(x-1);
}
bool vis[maxn][maxn][2];
inline long long DP(int i,int j,int k)
{
    if(j<0)
        return -1e16;
    if(i>n&&j==0)
        return 0;
    if(i>n||j==0)
        return -1e16;
    if(expr[i-1]=='+'||expr[i-1]=='-')
    {
        return max(DP(i+1,j-2,0),DP(i+1,j-1,1));
    }
    else
    {
        if(vis[i][j][k])
            return f[i][j][k];
        vis[i][j][k]=1;
        int it=0;
        if(i==1||expr[i-2]=='+'||expr[i-2]=='-')
            it=1;
        long long& ans=f[i][j][k];
        ans=-1e16;
        for(;it<10;it++)
        {
            if(j>=c[it])
            {
                ans=max(ans,DP(i+1,j-c[it],k)+1ll*it*power(wi[i-1])*(k==0?1:-1));
            }
        }
        return ans;
    }
}
int main()
{
    cin.tie(0);
    cout.tie(0);
    //ios_base::sync_with_stdio(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    rush()
    {
        scanf("%d",&n);
        scanf(" %s",expr);
        expr[n]='+';
        int sum=0;
        for(int i=0;i<=n;i++)
        {

            if(expr[i]=='+')
                sum+=2;
            else if(expr[i]=='-')
                sum++;
            else
            {
                sum+=c[expr[i]-'0'];
                continue;
            }
            int j=i-1,k=0;
            while(j>=0&&isdigit(expr[j]))
            {
                wi[j--]=k++;
            }
        }
        sum-=2;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=sum;j++)
            {
                for(int k=0;k<2;k++)
                {
                    vis[i][j][k]=0;
                }
            }
        }
        if(n==1&&expr[0]=='0')
            printf("0\n");
        else
            printf("%lld\n",DP(1,sum,0));
    }
}

AC的C++语言程序:

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
const int maxn = 1e5;
const ll inf = 0x7f7f7f7f7f7f7f7f;
const int inf1 = 0x7f7f7f7f;
 
int num[10]= {6,2,5,5,4,5,6,3,7,6};
int digit[60],cnt;
ll dp[1000][60][2],Max[2][15][100];
 
void get() {
	for(int i = 0; i <= 10; ++i)
		for(int j = 0; j <= 80; ++j) {
			Max[0][i][j] = inf1;
			Max[1][i][j] = -inf1;
		}
 
	for(int i = 1; i <= 10; ++i)
		for(int k = 1; k < 10; ++k) {
			Max[1][i][6 * (i - 1) + num[k]] = max(Max[1][i][6 * (i - 1) + num[k]],k * (ll)pow(10,i - 1));
			Max[0][i][6 * (i - 1) + num[k]] = min(Max[0][i][6 * (i - 1) + num[k]],k * (ll)pow(10,i - 1));
		}
 
	for(int i = 2; i <= 10; ++i)
		for(int j = 2; j <= 80; ++j)
			for(int k = 1; k < 10; ++k) {
				if(j >= num[k]) {
					if(Max[1][i - 1][j - num[k]] != -inf1) {
						if(Max[1][i][j] < Max[1][i - 1][j - num[k]] + k * (ll)pow(10,i - 1))
							Max[1][i][j] = Max[1][i - 1][j - num[k]] + k * (ll)pow(10,i - 1);
					}
					if(Max[0][i - 1][j - num[k]] != inf1) {
						if(Max[0][i][j] > Max[0][i - 1][j - num[k]] + k * (ll)pow(10,i - 1))
							Max[0][i][j] = Max[0][i - 1][j - num[k]] + k * (ll)pow(10,i - 1);
					}
				}
			}
}
 
ll dfs(int res,int pos,bool flag) {
	if(cnt == pos) {
		if(res >= 80)	return -inf1;
		if(abs(Max[flag][digit[pos]][res]) == inf1)	return -inf1;
		else {
			if(flag)
				return Max[flag][digit[pos]][res];
			else
				return -Max[flag][digit[pos]][res];
		}
	}
	if(dp[res][cnt - pos][flag] != -inf) 	return dp[res][cnt - pos][flag];
 
	ll tmp = -inf;
	for(int i = 1; i <= 80; ++i) {
		if(i >= res)	break;
		if(abs(Max[flag][digit[pos]][i]) == inf1)	continue;
 
		if(flag) {
			if(res >= i + 4) 	tmp = max(tmp,Max[flag][digit[pos]][i] + dfs(res - i - 2,pos + 1,true));
			if(res >= i + 3) 	tmp = max(tmp,Max[flag][digit[pos]][i] + dfs(res - i - 1,pos + 1,false));
		} else {
			if(res >= i + 4)	tmp = max(tmp,-Max[flag][digit[pos]][i] + dfs(res - i - 2,pos + 1,true));
			if(res >= i + 3)	tmp = max(tmp,-Max[flag][digit[pos]][i] + dfs(res - i - 1,pos + 1,false));
		}
//		cout<<res<<':'<<pos<<':'<<i<<':'<<Max[flag][digit[pos]][i]<<' '<<tmp<<endl;
	}
	dp[res][cnt - pos][flag] = tmp;
 
	return tmp;
}
 
ll solve(string str) {
	int total = 0;
	cnt = 0;
 
	memset(digit,0,sizeof(digit));
	for(int i = 0; i < str.size(); ++i) {
		if(isdigit(str[i])) {
			total += num[str[i] - '0'];
			++digit[cnt];
		} else {
			if(str[i] == '+')
				total += 2;
			else
				total += 1;
			++cnt;
		}
	}
 
	return dfs(total,0,true);
}
 
int main() {
	int t,n;
	string str;
 
	memset(Max[0],0x7f,sizeof(Max[0]));
	get();
 
	cin>>t;
	while(t--) {
		cin>>n>>str;
		for(int i = 0; i < 1000; ++i)
			for(int j = 0; j < 60; ++j)
				for(int k = 0; k < 2; ++k)
					dp[i][j][k] = -inf;
		cout<<solve(str)<<endl;
	}
 
	return 0;
}



E. Card Game



F. Information Transmitting



G. tsy’s number

题解链接:
南昌邀请赛网络赛 G. tsy’s number(莫比乌斯反演+线性筛)
[计蒜客] tsy’s number 解题报告 (莫比乌斯反演+数论分块)



H. Coloring Game

AC的C++语言程序:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<ctime>
#include<ctype.h>
#include<stdlib.h>
#include<bitset>
#include<algorithm>
#include<assert.h>
#include<numeric> //accumulate
#define endl "\n"
#define fi first
#define se second
#define FOR(i,s,t) for(int i=(s);i<=(t);++i)
#define mem(a,b) memset(a,b,sizeof(a))
#define rush() int MYTESENUM;scanf("%d",&MYTESENUM);while(MYTESENUM--)
using namespace std;
const long long mod=1e9+7;
long long solve(long long a,long long b)
{
    long long ret=0;
    if(b==0)
        return 1;
    if(b==1)
        return a;
    if(b&1)
    {
        ret=solve(a,b/2);
        return (((ret*ret)%mod)*a)%mod;
    }
    else
    {
        ret=solve(a,b/2);
        return (ret*ret)%mod;
    }
}

int main()
{
    cin.tie(0);
    cout.tie(0);
    //ios_base::sync_with_stdio(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);

    long long n;
    cin>>n;
    if(n==1)
        cout<<1;
    else
        cout<<(4*solve(3,n-2))%mod;
}

在这里插入图片描述
每个位置都有3种情况,第一个位置不能是第二种, 最后一个位置不能是第一种,所以一共有2 * 3^(n-2) * 2种情况。
AC的C++语言程序:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
 
ll pow(ll a, ll p){
	if (p == 0) return 1;
	ll t = pow(a, p/2);
	if (p &1) return t * t % mod * a % mod;
	return t * t % mod;
}
int main(void) {
	int n;
	cin >> n;
	if (n == 1) printf("1\n");
	else printf("%lld", 4ll * pow(3ll, (ll)n - 2) % mod);
	return 0;
}

AC的C++语言程序:

#include <iostream>
#include <set>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#define lo(i, n, m) for (int i = n; i < m; i++)
#define loe(i, n, m) for (int i = n; i <= m; i++)
#define rlo(i, n, m) for (int i = n - 1; i >= m; i--)
#define rloe(i, n, m) for (int i = n; i >= m; i--)
#define pb push_back
#define mk make_pair
#define clr(a, b) memset((a), (b), sizeof(a))
#define scd(x) scanf("%d", &x)
#define scs(x) scanf("%s", x)
#define sclf(x) scanf("%lf", &x)
#define scll(x) scanf("%lld", &x)
#define endl '\n'

using namespace std;
typedef long long LL;
template <class T>
inline void sw(T &a, T &b) {
    T t = a;
    a = b;
    b = t;
}
template <class T>
inline T mx(T a, T b) {return b < a ? a : b;}
template <class T>
inline T mi(T a, T b) {return a < b ? a : b;}
template <class T>
inline T mabs(T x) {return x < 0 ? -x : x;}
inline char gc() {
    char ch;
    while ((ch = getchar()) == ' ' || ch == '\n' || ch == '\t');
    return ch;
}
const int NIL = -1;
const LL MOD = 1e9 + 7;
inline int fp(int b, int p) {
    int ret = 1;
    do {
        if (p & 1) ret = (int)(1ll * b * ret % MOD);
        b = (int)(1ll * b * b % MOD);
    } while (p >>= 1);
    return ret;
}
// 使用快速模幂加速计算
int main(void) {
    int n;
    scd(n);
    if (n == 1) printf("1\n");
    else printf("%lld", 4ll * fp(3, n - 2) % MOD);
    return 0;
}



I. Max answer

AC的C++语言程序:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<ctime>
#include<ctype.h>
#include<stdlib.h>
#include<bitset>
#include<algorithm>
#include<assert.h>
#include<numeric> //accumulate
#define endl "\n"
#define fi first
#define se second
#define int long long
#define FOR(i,s,t) for(int i=(s);i<=(t);++i)
#define mem(a,b) memset(a,b,sizeof(a))
#define rush() int MYTESENUM;scanf("%d",&MYTESENUM);while(MYTESENUM--)
using namespace std;
const int maxn=500000+5;
int a[maxn];
struct node
{
    int sum,mi,mx;
};
struct segmenttree
{
    #define ls o<<1
    #define rs o<<1|1
    #define lss ls,l,mid
    #define rss rs,mid+1,r
    int sum[maxn<<2];
    int val[maxn<<2];
    int val1[maxn<<2];
    inline void pushdown(int o)
    {
        sum[o]=sum[ls]+sum[rs];
        val[o]=max(val[ls],sum[ls]+val[rs]);
        val1[o]=min(val1[ls],sum[ls]+val1[rs]);
    }
    inline void build(int o,int l,int r)
    {
        if(l==r)
        {
            sum[o]=a[l];
            val[o]=a[l];
            val1[o]=a[l];
            return ;
        }
        int mid=l+r>>1;
        build(lss);
        build(rss);
        pushdown(o);
    }
    int ql,qr;
    inline node query(int o,int l,int r)
    {
        if(l>=ql&&r<=qr)
        {
            return (node){sum[o],val1[o],val[o]};
        }
        int mid=l+r>>1;
        node lt,rt;
        if(mid>=ql)
            lt=query(lss);
        else
            return query(rss);
        if(qr>mid)
            rt=query(rss);
        else
            return lt;
        return (node){lt.sum+rt.sum,min(lt.mi,lt.sum+rt.mi),max(lt.mx,rt.mx+lt.sum)};
    }
};
segmenttree T1,T2;
int l[maxn],r[maxn];
int n;
int32_t main()
{
    cin.tie(0);
    cout.tie(0);
    //ios_base::sync_with_stdio(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    cin>>n;
    for(int i=1; i<=n; i++)
    {
        cin>>a[i];
        l[i]=r[i]=i;
    }
    for(int i=2; i<=n; i++)
    {
        int now=i;
        while(now>1&&a[i]<=a[now-1])
            now=l[now-1];
        l[i]=now;
    }
    for(int i=n-1; i; i--)
    {
        int now=i;
        while(now<n&&a[i]<=a[now+1])
            now=r[now+1];
        r[i]=now;
    }
    T1.build(1,1,n);
    reverse(a+1,a+n+1);
    T2.build(1,1,n);
    reverse(a+1,a+n+1);
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==0)
            continue;
        if(a[i]>0)
        {
            int lg,rg;
            if(l[i]==i)
            lg=0;
            else
            {
                T2.ql=n-(i-1)+1;
                T2.qr=n-l[i]+1;
                lg=T2.query(1,1,n).mx;
            }
            T1.ql=i,T1.qr=r[i];
            rg=T1.query(1,1,n).mx;
            ans=max(ans,(lg+rg)*a[i]);
        }
        else
        {
            int lg,rg;
            if(l[i]==i)
            lg=0;
            else
            {
                T2.ql=n-(i-1)+1;
                T2.qr=n-l[i]+1;
                lg=T2.query(1,1,n).mi;
            }
            T1.ql=i,T1.qr=r[i];
            rg=T1.query(1,1,n).mi;
            ans=max(ans,(lg+rg)*a[i]);
        }
    }
    cout<<ans;
}

维护6个值
L[i]—— i左面比a[i]小的第一个数的位置
R[i]—— i右面比a[i]小的第一个数的位置
lmax[i]—— 以i为右端点的区间最大值
lmin[i]—— 以i为右端点的区间最小值
rmax[i]—— 以i为左端点的区间最大值
rmin[i]—— 以i为左端点的区间最小值
如果 a[i] > 0 ans = max(ans, a[i] * (sum[min(R[i] - 1, rmax[i])] - sum[max(L[i] + 1, lmax[i])-1]));
a[i] < 0 ans = max(ans, a[i] * (sum[min(R[i] - 1, rmin[i])] - sum[max(L[i] + 1, lmin[i])-1]));

#include <bits/stdc++.h>
 
using namespace std;
const int maxn =5e5+10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
int L[maxn], R[maxn], lmax[maxn], rmax[maxn], lmin[maxn], rmin[maxn], a[maxn];
ll sum[maxn];
stack<pair<int, int> > s;
int n;
 
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
        sum[i] = sum[i - 1] + a[i];
    }
    s.push({1, a[1]});
    R[n] = n+1;
    a[n+1] = -INF;
    a[0] = -INF;
    for (int i = 2; i <= n+1; i++) {
        while (!s.empty() && s.top().second > a[i]){
            R[s.top().first] = i, s.pop();
        }
        s.push({i,a[i]});
    }
    s.push({n, a[n]});
 
    for (int i = n-1; i >= 1; i--) {
        while (!s.empty() && s.top().second > a[i]){
            L[s.top().first] = i, s.pop();
        }
        s.push({i,a[i]});
    }
    lmax[1] = 1;
    for (int i= 2; i <= n; i++){
        if (sum[i - 1] - sum[lmax[i - 1] - 1] > 0) lmax[i] = lmax[i -1];
        else lmax[i] = i;
    }
    lmin[1] = 1;
    for (int i = 2; i <= n; i++){
        if (sum[i - 1] - sum[lmin[i - 1] - 1 ]< 0) lmin[i] = lmin[i-1];
        else lmin[i] = i;
    }
    rmax[n] = n;
    for (int i =n -1; i>=1; i--) {
        if (sum[rmax[i+1]] - sum[i] > 0) rmax[i] = rmax[i + 1];
        else rmax[i] = i;
    }
    rmin[n] = n;
    for (int i = n - 1; i>=1; i--){
        if (sum[rmin[i+1]] - sum[i] < 0) rmin[i] = rmin[i + 1];
        else rmin[i] = i;
    }
   ll ans = 0;
    for (int i = 1; i <= n; i++){
        if (a[i] > 0)  ans = max(ans, (ll)a[i] * (sum[min(R[i] - 1, rmax[i])] - sum[max(L[i] + 1, lmax[i])-1]));
        else if (a[i] < 0) ans = max(ans, (ll)a[i] * (sum[min(R[i] - 1, rmin[i])] - sum[max(L[i] + 1, lmin[i])-1]));
    }
    printf("%lld\n", ans);
    return 0;
}



J. Distance on the tree

离线+线段树+树链剖分。参考链接:dfs序 与 树链剖分 例题 Distance on the tree
AC的C++语言程序:

#include <bits/stdc++.h>
using namespace std;
 
const int maxn  = 2e5+2;
const int maxm = 1e5+2;
struct Ques{
    int l ,r, k, id;
}Q[maxm];
 
struct node{
    int u, v, w;
}E[maxn];
 
int n , m, last;
bool cmp(const Ques A, const Ques B){
    return A.k < B.k;
}
 
bool cmp2(const node A, const node B){
    return A.w < B.w;
}
int Ans[maxn];
vector <int > edge[maxn];
int sz[maxn], son[maxn], pos[maxn], tot, dep[maxn], fa[maxn], top[maxn];
 
void dfs(int x, int u){
    sz[x] = 1;son[x] = 0;
    fa[x] = u;
    for (int i = 0; i< edge[x].size(); i++){
        if (edge[x][i] == fa[x]) continue;
        dep[edge[x][i]] = dep[x] + 1;
        dfs(edge[x][i], x);
        sz[x] += sz[edge[x][i]];
        if (sz[edge[x][i]] > sz[son[x]]) son[x] = edge[x][i];
    }
}
 
void dfs1(int x, int now_top) {
    top[x] = now_top;
    pos[x] = ++tot;
    if (son[x]) dfs1(son[x], now_top);
    for (int i = 0; i< edge[x].size(); i++){
        if (edge[x][i] == fa[x]) continue;
        if (edge[x][i] != son[x]){
            dfs1(edge[x][i], edge[x][i]);
        }
    }
}
 
int tr[maxn * 4];
 
void add(int l , int r , int p ,int a, int b){
    if (l > a || r < a) return;
    if (l == a && r == a){
        tr[p] = b;
        return ;
    }
    int mid = (l +r) / 2;
    if (a <= mid) add(l, mid , p * 2 , a, b);
    else add(mid +1, r, p*2+1, a, b);
    tr[p] =tr[p *2] + tr[p * 2+1];
}
 
int query(int l, int r, int p , int a, int b){
    if (l > b || r < a) return 0;
    if(l >= a && r <=b){
        return tr[p];
    }
    int mid = (l +r) /2;
    if (b <= mid) return query(l, mid, p * 2, a, b);
    else if (a > mid) return query(mid + 1, r, p *2 + 1, a, b);
    else return query(l, mid, p * 2, a, b) + query(mid+1, r, p * 2 +1, a, b);
}
 
int ques_ans(int u, int v){
    int f1 = top[u], f2 = top[v], ans = 0;
    while (f1 != f2){
        if (dep[f1] < dep[f2]){
            swap(u, v);
            swap(f1,f2);
        }
        ans += query(1, n, 1, pos[f1], pos[u]);
        u = fa[f1];f1 = top[u];
    }
    if (u == v) return ans;
    if (dep[u] > dep[v]) swap(u, v);
    return ans + query(1, n, 1, pos[son[u]], pos[v]);
}
 
int main() {
    scanf("%d%d", &n, &m);
    for (int  i = 1; i< n;i++){
        int u, v, w;
        scanf("%d%d%d", &u,&v,&w);
        edge[u].push_back(v);
        edge[v].push_back(u);
        E[i].u = u;
        E[i].v = v;
        E[i].w = w;
    }
    sort(E+1,E+n, cmp2);
    dfs(1, 1);
    dfs1(1, 1);
    for (int i = 1; i <= m;i++){
        scanf("%d%d%d", &Q[i].l, &Q[i].r, &Q[i].k);
        Q[i].id = i;
    }
    sort(Q+1, Q+1+m, cmp);
    last = 0;
    for (int i =1; i<=m;i++){
        for (int j = last+1; j < n; j++){
            if (E[j].w > Q[i].k) break;
            if (dep[E[j].u] > dep[E[j].v]) swap(E[j].u, E[j].v);
            add(1, n, 1, pos[E[j].v], 1);
            last = j;
        }
        Ans[Q[i].id] = ques_ans(Q[i].l, Q[i].r);
    }
    for (int i = 1; i <= m;i++){
        printf("%d\n", Ans[i]);
    }
    return 0;
}

AC的C++语言程序:

#include <bits/stdc++.h>
#define lo(i, n, m) for (int i = n; i < m; i++)
#define loe(i, n, m) for (int i = n; i <= m; i++)
#define rlo(i, n, m) for (int i = n - 1; i >= m; i--)
#define rloe(i, n, m) for (int i = n; i >= m; i--)
#define pb push_back
#define mk make_pair
#define clr(a, b) memset((a), (b), sizeof(a))
#define scd(x) scanf("%d", &x)
#define scs(x) scanf("%s", x)
#define sclf(x) scanf("%lf", &x)
#define scll(x) scanf("%lld", &x)
#define endl '\n'

using namespace std;
typedef long long LL;
template <class T>
inline void sw(T &a, T &b) {
    T t = a;
    a = b;
    b = t;
}
template <class T>
inline T mx(T a, T b) {return b < a ? a : b;}
template <class T>
inline T mi(T a, T b) {return a < b ? a : b;}
template <class T>
inline T mabs(T x) {return x < 0 ? -x : x;}
inline char gc() {
    char ch;
    while ((ch = getchar()) == ' ' || ch == '\n' || ch == '\t');
    return ch;
}

// Fast IO类
struct _IO {
    char buf[20], ch;
    _IO &operator >> (int &x) {
        x = 0;
        while ((ch = getchar()) < '0' || ch > '9');
        while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
        return *this;
    }
    _IO &operator >> (long long &x) {
        x = 0;
        while ((ch = getchar()) <'0' || ch > '9');
        while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
        return *this;
    }
    _IO &operator << (int x) {
        int cur = 0;
        if (!x) {
            putchar('0');
            return *this;
        }
        while (x) buf[cur++] = x % 10 + '0', x /= 10;
        while (--cur >= 0) putchar(buf[cur]);
        return *this;
    }
    _IO &operator << (long long x) {
        int cur = 0;
        if (!x) {
            putchar('0');
            return *this;
        }
        while (x) buf[cur++] = x % 10 + '0', x /= 10;
        while (--cur >= 0) putchar(buf[cur]);
        return *this;
    }
    _IO &operator << (char c) {
        putchar(c);
        return *this;
    }
    _IO &operator << (const char *str) {
        for (int i = 0; str[i]; i++) putchar(str[i]);
        return *this;
    }
} IO;

const int NIL = -1;
const int LIM = 1e5 + 10;
const int SIZE = LIM << 1;
// 边的结构体
// 两个数组,edge[]是使用链式前向星存图用的数组(每条边会加入两个),eds用来存放单条边(相当于每条边只存放一次)
struct EDGE {
    int u, nxt, v, w;
    EDGE(int nid = 0, int nv = 0, int nw = 0) : nxt(nid), v(nv), w(nw) {}
    bool operator < (const EDGE &e) const {
        return w < e.w;
    }
} edge[SIZE], eds[LIM];
// que存放队列,g是链式前向星定义的图的每个链的表头,
// idx[i]是树链剖分后结点i所在链中的位置,这里深度大的结点编号小
// dep[i]是结点i的深度
// sz[i]是结点i的子树的大小
// belong[i]是结点i所属的链的编号(从0开始)
// fa[i]是顶点i在链中的父结点
// head[i]是顶点i所在链中深度最小的结点
// len[i]是编号为i的链的长度
int que[LIM], g[LIM], idx[LIM], dep[LIM], sz[LIM], belong[LIM], fa[LIM], head[LIM], len[LIM];
bool vis[LIM];
// l和r标记队尾和队头
int l, r, cnt;
int ec = 0;
int n, m, u, v, w;

// 前向星加边函数
inline void add(int u, int v, int w) {
    int pos = ec++;
    edge[pos] = EDGE(g[u], v, w);
    edge[pos].u = u;
    g[u] = pos;
}

// BFS版树链剖分
inline void split() {
    clr(dep, NIL);
    l = 0, r = 1;
    que[r] = 1;
    dep[1] = 0;
    fa[1] = NIL;
    // start bfs
    while (l < r) {
        int x = que[++l];
        vis[x] = false;
        for (int i = g[x]; i != NIL; i = edge[i].nxt) {
            if (dep[edge[i].v] == NIL) {
                // push into queue
                que[++r] = edge[i].v, dep[edge[i].v] = dep[x] + 1;
                fa[edge[i].v] = x;
            }
        }
    }
    // do split
    for (int i = n; i; i--) {
        int x = que[i], p = NIL;
        sz[x] = 1;
        for (int j = g[x]; j != NIL; j = edge[j].nxt) {
            if (vis[edge[j].v]) {
                sz[x] += sz[edge[j].v];
                if (p == NIL || sz[edge[j].v] > sz[p])
                p = edge[j].v;
            }
        }
        if (p == NIL) {
            idx[x] = len[++cnt] = 1;
            belong[head[cnt] = x] = cnt;
        } else {
            idx[x] = ++len[belong[x] = belong[p]];
            head[belong[x]] = x;
        }
        vis[x] = true;
    }
}

// 存储询问的结构体
struct QUE {
    int u, v, w, id;
    QUE(int nu = 0, int nv = 0, int nw = 0, int nid = 0) : u(nu), v(nv), w(nw), id(nid) {}
    bool operator < (const QUE &q) const {
        return w < q.w;
    }
};
vector<QUE> ques;
// 存储答案的数组
int qans[LIM];
// 树链长度的前缀和,用来给每条树链中的结点进行编号,将问题转化为区间查询问题
int presum[LIM];

// 用来计算结点x在线段树中的编号
inline int ID(int x) {
    return presum[belong[x] - 1] + idx[x];
}

// 线段树的结构体
struct Node {
    int l, r, dat;
} sgtree[SIZE * 4];

// 线段树向上合并操作的实用函数
inline void pushup(int idx) {
    sgtree[idx].dat = sgtree[idx << 1].dat + sgtree[idx << 1 | 1].dat;
}

// 构建线段树的实用函数
void buildUtil(int l, int r, int idx) {
    Node &crt = sgtree[idx];
    if (l == r) {
        crt.l = l;
        crt.r = r;
        sgtree[idx].dat = 0;
        return;
    }
    int mid = (l + r) >> 1;
    buildUtil(l, mid, idx << 1);
    buildUtil(mid + 1, r, idx << 1 | 1);
    pushup(idx);
    // push up left and right bound
    crt.l = sgtree[idx << 1].l;
    crt.r = sgtree[idx << 1 | 1].r;
}

// 构建线段树的接口函数
void build(int l, int r) {
    // memset(sgtree, 0, sizeof sgtree);
    buildUtil(l, r, 1);
}

// 单点更新实用函数
void updateUtil(int p, int val, int idx) {
    Node &crt = sgtree[idx];
    if (crt.l == crt.r) {
        sgtree[idx].dat += val;
        return;
    }
    int mid = (crt.l + crt.r) >> 1;
    if (p <= mid) updateUtil(p, val, idx << 1);
    else updateUtil(p, val, idx << 1 | 1);
    pushup(idx);
}

// 单点更新的接口函数
inline void update(int p, int val) {
    updateUtil(p, val, 1);
}

// 区间查询的实用函数
int queryUtil(int l, int r, int idx) {
    Node &crt = sgtree[idx];
    if (crt.l >= l && crt.r <= r) {
        return crt.dat;
    }
    int mid = (crt.l + crt.r) >> 1;
    if (r <= mid) return queryUtil(l, r, idx << 1);
    else if (l > mid) return queryUtil(l, r, idx << 1 | 1);
    else return queryUtil(l, mid, idx << 1) + queryUtil(mid + 1, r, idx << 1 | 1);
}

// 区间查询的接口函数
inline int query(int l, int r) {
    if (l > r) sw(l, r);
    return queryUtil(l, r, 1);
}

// 单点查询的实用函数
int queryUtil(int p, int idx) {
    Node &crt = sgtree[idx];
    if (crt.l == crt.r) {
        return crt.dat;
    }
    int mid = (crt.l + crt.r) >> 1;
    if (p <= mid) return queryUtil(p, idx << 1);
    else return queryUtil(p, idx << 1 | 1);
}

// 单点查询的实用函数
inline int query(int p) {
    return queryUtil(p, 1);
}

/**
* 树链剖分将结点编号,之后将边和询问按权值递增排序,离线查询
* 将当前加入的边标记为1,记录到深度较深的结点上,
* 问题转化为区间查询问题
*/
int main(void) {
    IO >> n >> m;
    clr(g, NIL);
    lo(i, 1, n) {
        IO >> u >> v >> w;
        eds[i].u = u, eds[i].v = v, eds[i].w = w;
        add(u, v, w), add(v, u, w);
    }
    split();
    loe(i, 1, cnt) presum[i] = presum[i - 1] + len[i];
    // 对边按权值排序
    sort(eds + 1, eds + n);
    // load querys
    lo(i, 0, m) {
        IO >> u >> v >> w;
        ques.pb(QUE(u, v, w, i));
    }
    // 对询问按权值排序
    sort(ques.begin(), ques.end());
    int pos = 1;
    build(1, presum[cnt]);
    lo(i, 0, ques.size()) {
        QUE &q = ques[i];
        while (pos < n && eds[pos].w <= ques[i].w) {
            EDGE &e = eds[pos++];
            if (dep[e.u] > dep[e.v]) update(ID(e.u), 1);
            else update(ID(e.v), 1);
        }
        if (belong[q.u] == belong[q.v]) {
            if (dep[q.v] > dep[q.u]) sw(q.u, q.v);
            qans[q.id] = query(ID(q.u), ID(q.v)) - query(ID(q.v));
        } else {
            while (belong[q.u] != belong[q.v]) {
                if (dep[head[belong[q.v]]] > dep[head[belong[q.u]]]) sw(q.u, q.v);
                qans[q.id] += query(ID(q.u), ID(head[belong[q.u]]));
                q.u = fa[head[belong[q.u]]];
            }
            if (dep[q.v] > dep[q.u]) sw(q.u, q.v);
            qans[q.id] += query(ID(q.u), ID(q.v)) - query(ID(q.v));
        }
    }
    lo(i, 0, ques.size()) IO << qans[i] << endl;
    return 0;
}



K. MORE XOR

AC的C++语言程序:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<ctime>
#include<ctype.h>
#include<stdlib.h>
#include<bitset>
#include<algorithm>
#include<assert.h>
#include<numeric> //accumulate
#define endl "\n"
#define fi first
#define se second
#define FOR(i,s,t) for(int i=(s);i<=(t);++i)
#define mem(a,b) memset(a,b,sizeof(a))
#define rush() int MYTESENUM;scanf("%d",&MYTESENUM);while(MYTESENUM--)
#define debug(x) printf("%d\n",x)
using namespace std;
const int maxn=100000+10;
int n;
int pref[maxn];
int main()
{
    cin.tie(0);
    cout.tie(0);
    //ios_base::sync_with_stdio(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    rush()
    {
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&pref[i]);
        }
        for(int i=4;i<=n;i++)
        {
            pref[i]^=pref[i-4];
        }
        int q;
        scanf("%d", &q);
        while( q-- )
        {
            int l,r;
            scanf("%d %d", &l, &r);
            int len=r-l+1;
            int ans;
            if(len%4==0)
            {
                ans=0;
            }
            else if(len%4==1)
            {
                if(l>=4)
                    ans=pref[r]^pref[l-4];
                else
                    ans=pref[r];
            }
            else if(len%4==2)
            {
                if(l>=3)
                    ans=pref[r]^pref[l-3];
                else
                    ans=pref[r];
                if(l>=4)
                    ans^=pref[r-1]^pref[l-4];
                else
                    ans^=pref[r-1];
            }
            else
            {
                if(l>=3)
                    ans=pref[r-1]^pref[l-3];
                else
                    ans=pref[r-1];
            }
            printf("%d\n", ans);
        }

    }
}

很暴力的:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
typedef long long ll;
ll T, n,q,le,ri,mid,ans,sum,k;
ll a[maxn], f[4][5][maxn],fu;
 
int main() {
	cin >> T;
	int g[4][4][4]={1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0};
	while (T--){
		scanf("%lld", &n);
		sum = 0;
		for (int i =1; i <= n; i++)
			scanf("%lld", &a[i]), sum = sum ^ a[i];
		for (int k = 0; k <4;k++)
			for (int i  = 0; i < 4; i++)
				for (int j = 1; j <=n;j++)
					f[k][i][j] = f[k][i][j-1]^(a[j]*g[k][i][(j-1)%4]);
		scanf("%lld", &q);
		while (q--){
			scanf("%lld%lld", &le ,&ri) ;
			mid = ri - le;
			ans =sum;
			printf("%lld\n", (f[(le-1)%4][mid%4][ri]^f[(le-1)%4][mid%4][le-1]) );
		}
	}
	return 0;
} 



L. qiqi’tree
几何模拟树的生长。

#include <bits/stdc++.h>
 
using namespace std;
const int maxn = 2e6;
struct branch{
    double x1, y1, x2, y2;
    double getLength(){
        return sqrt((x1 - x2) *(x1 - x2) + (y1 -y2) * (y1 - y2));
    }
};
 
struct line{
    double x0, y0, k;
}L;
int n;
int isUpLine(double x, double y, line L){
    if (y > L.k * x - L.k * L.x0 + L.y0) return 1;
    else if (y < L.k * x - L.k * L.x0 + L.y0) return -1;
    return 0;
}
 
double dis(double x, double y, line L){
    double ans = L.k * x - y - L.k * L.x0 + L.y0;
    return fabs(ans) / sqrt(L.k * L.k +1);
}
 
double restLength(branch a, line b){
    if (isUpLine(a.x1, a.y1, b) < 0 && isUpLine(a.x2, a.y2, b) == 0) return a.getLength();
    if (isUpLine(a.x1, a.y1, b) < 0 && isUpLine(a.x2, a.y2, b) > 0) {
        double l1 = dis(a.x1, a.y1, b);
        double l2 = dis(a.x2, a.y2, b);
        return a.getLength()*l1/(l1+l2);
    }
}
 
branch q[maxn],nxt[maxn];
int tot, tot1;
double Ans =0;
void cut(){
    for (int i = 0; i < tot; i++){
        if (isUpLine(q[i].x1, q[i].y1, L) * isUpLine(q[i].x2, q[i].y2, L) >0){
            Ans += q[i].getLength();
            nxt[tot1++] = q[i];
        }
        else if (isUpLine(q[i].x1, q[i].y1, L) <0 && isUpLine(q[i].x2, q[i].y2, L) ==0){
            Ans += q[i].getLength();
        }else if (isUpLine(q[i].x1, q[i].y1, L) <0 && isUpLine(q[i].x2, q[i].y2, L) > 0){
            Ans += restLength(q[i], L);
        }
    }
    tot=0;
    for (int i = 0; i < tot1; i++){
        double x = (nxt[i].x2 - nxt[i].x1)/4;
        double y = (nxt[i].y2 - nxt[i].y1)/4;
        q[tot++] = {nxt[i].x2, nxt[i].y2, x+nxt[i].x2, y+nxt[i].y2};
        q[tot++] = {nxt[i].x2, nxt[i].y2, 1.0/2.0 * x - sqrt(3.0)/2.0 * y + nxt[i].x2 , sqrt(3.0)/2.0 * x + 1.0/2.0*y + nxt[i].y2};
       // cout <<q[tot-1].x1 << " " <<q[tot-1].y1<< " " << q[tot-1].x2 <<" "<< q[tot-1].y2 << endl;
        q[tot++] = {nxt[i].x2, nxt[i].y2, 1.0/2.0 * x + sqrt(3.0)/2.0 * y + nxt[i].x2 , -sqrt(3.0)/2.0 * x + 1.0/2.0*y + nxt[i].y2};
    }
    tot1 =0;
}
int main()
{
    int T;
    cin >> T;
    while (T--){
        double len=0;tot=0,tot1=0;
        scanf("%lf", &len);
        scanf("%d%lf%lf%lf", &n, &L.x0, &L.y0, &L.k);
        branch fir({0.0,0.0,0.0,len});
        q[tot++] = fir;Ans =0;
        for (int i = 1; i<=n;i++){
            cut();
        }
        printf("%.6lf\n", Ans);
    }
    return 0;
}



M. Subsequence

AC的C++语言程序:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<ctime>
#include<ctype.h>
#include<stdlib.h>
#include<bitset>
#include<algorithm>
#include<assert.h>
#include<numeric> //accumulate
#define endl "\n"
#define fi first
#define se second
#define FOR(i,s,t) for(int i=(s);i<=(t);++i)
#define mem(a,b) memset(a,b,sizeof(a))
#define rush() int MYTESENUM;scanf("%d",&MYTESENUM);while(MYTESENUM--)
using namespace std;
const int maxn=100000+5;
char s[maxn];
char t[maxn];
int f[maxn][30];
inline bool check()
{
    int p=1;
    for(int i=1;t[i];i++)
    {
        p=f[p][t[i]-'a'];
        if(p==0)
            return 0;
        p++;
    }
    return 1;
}
int main()
{
    cin.tie(0);
    cout.tie(0);
    //ios_base::sync_with_stdio(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    scanf("%s",s+1);
    int n=strlen(s+1);
    for(int i=n;i;i--)
    {
        for(int j=0;j<26;j++)
        {
            if(s[i]==j+'a')
            {
                f[i][j]=i;
            }
            else
            {
                f[i][j]=f[i+1][j];
            }
        }
    }
    rush()
    {
        scanf(" %s",t+1);
        if(check())
            puts("YES");
        else
            puts("NO");

    }
}

预处理第一串st[i]后26个字符第一次出现的地方。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
char st[maxn], st2[1002];
int now[26], nxt[maxn][26];
int n;
int main() {
	scanf("%s" , st);
	int l1 = strlen(st);
	for (int i = 0 ; i < 26; i++) now[i] = l1;
	for (int i = l1 -1 ; i >=0; i--){
		for (int j = 0; j < 26;j++){
			 nxt[i][j] = now[j];
		}
		now[st[i] - 'a'] = i;
	}
	scanf("%d", &n);
	for (int i = 0;i <n;i++){
		scanf("%s", st2);
		int l2 = strlen(st2);
		int s1, s2;
		s1 = s2 = 0;
		if (l2 > l1) {
			printf("NO\n");
			continue;
		}
		s1 = now[st2[0] - 'a'];
		for (int j = 1; j < l2; j++){
			s1 = nxt[s1][st2[j] -'a'];
			if (s1 == l1) break; 
		}
		if (s1 != l1) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
} 



参考链接
The Preliminary Contest for ICPC China Nanchang National Invitational 南昌网络赛2019
2019南昌邀请赛网络赛 个人记录(附官方题解)

猜你喜欢

转载自blog.csdn.net/tigerisland45/article/details/89473637
今日推荐