2018CCPC 中国大学生程序设计竞赛 网络赛

链接
1.括号序列贪心/CF&51nod原题
【分析】:
贪心,每次到i的时候,假如你要在i里面要卖掉股票,获益是a[i], 肯定要在前面要么:1)把已经卖了的变成不买不卖,需要-a[j], 2)把已经不买不卖的变成买,需要-a[j]
【原题链接】:CF&E
CF&D
51nod高卖低买

3.构造/封闭运算/费马小定理下模意义/重新定义+和 *
【题意】:
输入:素数p
要求构造规则a[p*p],使其满足:(m+n)p=mp+n^p
a的含义:
a[i][j] = (i-1) + (j-1),a[p+i][j] = (i-1) * (j-1)
【 + 意义】加法全0
【 * 意义】

【分析】:(转载自 http://www.cnblogs.com/xiuwenli/p/9534918.html)
给定的p是素数,要求给定一个加法运算表和乘法运算表,使(m+n)p=mp+np(0≤m,n<p)。
因为给定的p是素数,根据费马小定理得 (m+n)p−1≡1(mod p)
因此,(m+n)p≡m+n (mod p),
同时,mp+np≡m+n (mod p)。
所以在模p意义下,(m+n)p=mp+np(0≤m,n<p) 恒成立,且加法运算与乘法运算封闭。

等式两边%p,发现左右都是n+m。等式成立,所以所需的加法群和乘法群就很明显
就是%p意义下的加法群和乘法群。

4.费马大定理/勾股数定理/15浙工大校赛原题
【原题链接】n==2的情况
Codeforces Round #368 (Div. 2)C. Pythagorean Triples
给出一个整数问是否能找出另外两个数使得构成一组勾股数。如不能则输出-1,反之,则输出任意符合的两个数。

7.分组后单调队列/倍增/线段树

9.子树/树形dp与阶乘/dfs/结论题

10.树状数组/线段树优化dp

【1001】

#include <iostream>
#include <cstdio>
#include <queue>
#include <set>
#include <cstring>
using namespace std;
typedef long long ll;
multiset<pair<int,bool> > st;
const int maxn = 1e5 + 4;
int t, n, a;
int main()
{
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
    int t;
    scanf("%d", &t);
    while(t--)
    {
        st.clear();
        ll ans = 0;
        int cnt = 0;
        scanf("%d", &n);
        for(size_t i = 0; i < n; i++)
        {
            ll a;
            scanf("%lld", &a);
            if(!st.empty()&&(*st.begin()).first<a)
            {
                ans += (a - (*st.begin()).first);
                if((*st.begin()).second==true)
                    cnt++;
                st.erase(st.begin());
                st.insert(make_pair(a, true));
                st.insert(make_pair(a, false));
            }
            else
            {
                st.insert(make_pair(a, true));
            }
        }
        printf("%lld %d
", ans, cnt * 2);
    }
    return 0;
}

【1003】

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;

int main()
{
    int T;
    scanf("%d", &T);
    for(int ti=0;ti<T;ti++)
    {
        int p;
        scanf("%d", &p);
        for (int i = 0; i < p; i++)
        {
            for (int j = 0; j < p; j++)
            {
                if (j)printf(" ");
                printf("%d", (i + j) % p);
            }
            printf("
");
        }
        for (int i = 0; i < p; i++)
        {
            for (int j = 0; j < p; j++)
            {
                if (j)printf(" ");
                printf("%d", (i*j) % p);
            }
            printf("
");
        }
    }
}

【1004】

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        ll a, n;

        scanf("%lld%lld", &n, &a);
        if (n > 2)printf("-1 -1
");
        else
        {
            if (n == 0)printf("-1 -1
");
            else if (n == 1)printf("%lld %lld
", 1, a + 1);
            else if (n == 2)
            {
                if (a & 1)
                {
                    ll x = (a - 1) / 2;
                    ll c = x*x + (x + 1)*(x + 1);
                    printf("%lld %lld
", c - 1, c);
                }
                else
                {
                    ll x = a / 2;
                    printf("%lld %lld
", x*x - 1, x*x + 1);
                }
            }
        }
    }
}

【1007-单调队列】

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

int a[10010];
int n,m,k;
long long s;
long long ans;
bool vis[10010];
long long sum[30010];
int b[30010];
void gao(vector<int> vec) {
	int sz = vec.size();
	sum[0] = 0;
	for (int i = 1; i < 3*sz; i++) {
		sum[i] = sum[i-1] + a[vec[(i-1)%sz]];
	}

	long long s1 = 0;
	long long tt = m/sz-1;
	if (tt < 0) tt = 0;
	s1 = tt*sum[sz];
	if (s1 < 0) s1 = 0;

	int lm = m - tt*sz;

	long long ms = 0;
	int st, ed;
	st = 0; ed = 0;
	b[ed++] = 0;
	for (int i = 1; i < 3*sz; i++) {
		while (st < ed && b[st] < i - lm)st++;
		ms = max(ms, sum[i] - sum[b[st]]);
		while (st < ed && sum[b[ed-1]] >= sum[i])ed--;
		b[ed++] = i;
	}
	ans = min(ans, max(0LL, s - s1 - ms));
}

int main() {
	int T;
	scanf("%d", &T);
	int iCase = 0;
	while (T--) {
		iCase++;
		cin>>n>>s>>m>>k;
		for (int i = 0; i < n; i++)
			scanf("%d", &a[i]);
		ans = s;
		memset(vis, false, sizeof(vis));
		for (int i = 0; i < n; i++) {
			if (vis[i])continue;
			vector<int>vec;
			int now = i;
			vec.push_back(i);
			vis[now] = true;
			now = (now+k)%n;
			while (now != i) {
				vec.push_back(now);
				vis[now] = true;
				now = (now+k)%n;
			}
			gao(vec);
		}
		printf("Case #%d: ", iCase);
		cout<<ans<<endl;
	}
	return 0;
}

【线段树】

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const ll maxn = 4e4+7;
struct Segment_tree
{
    struct Node
    {
        ll Max;
        ll Size,son[2];
        void init()
        {
            son[0]=son[1]=Size=Max=0;
        }
    } T[maxn*4];
    ll cnt,root;

    void init(ll l,ll r,ll *a)
    {
        cnt=0;
        root=build(l,r,a);
    }

    inline void update(ll pos)
    {
        if(T[pos].Size==1)return ;
        T[pos].Max=max(T[T[pos].son[0]].Max,T[T[pos].son[1]].Max);
    }

    inline ll build(ll l,ll r,ll *a)
    {
        ll pos=++cnt;
        T[pos].init();
        T[pos].Size=r-l+1;
        if(l==r)
        {
            T[pos].Max=a[l];
            return pos;
        }
        ll mid=(l+r)>>1;
        T[pos].son[0]=build(l,mid,a);
        T[pos].son[1]=build(mid+1,r,a);
        update(pos);
        return pos;
    }

    void cov(ll L,ll R,ll i,ll v,ll pos=1)
    {
        if(L==R)
        {
            T[pos].Max=max(T[pos].Max,v);
            return ;
        }
        ll mid=(L+R)>>1;
        if(i<=mid)
            cov(L,mid,i,v,T[pos].son[0]);
        else
            cov(mid+1,R,i,v,T[pos].son[1]);
        update(pos);
    }

    ll query_Max(ll L,ll R,ll l,ll r,ll pos=1)
    {
        if(l>r)return 0;
        if(L==l&&R==r)
        {
            return T[pos].Max;
        }
        ll mid=(L+R)>>1;
        if(r<=mid)
            return query_Max(L,mid,l,r,T[pos].son[0]);
        else if(l>mid)
            return query_Max(mid+1,R,l,r,T[pos].son[1]);
        else
            return max(query_Max(L,mid,l,mid,T[pos].son[0]),query_Max(mid+1,R,mid+1,r,T[pos].son[1]));
    }
}tree;
ll a[maxn],ans;
ll n,s,m,k;
bool vis[maxn];
ll p[maxn],sum[maxn];
ll solve(ll start){

    ll sz=0;
    for(ll i=start;!vis[i];i=(i+k)%n){
        vis[i]=1;
        p[++sz]=i;
    }
    for(ll i=sz+1;i<=sz*4;i++){
        p[i]=p[i-sz];
    }
    for(ll i=1;i<=sz*4;i++)
        sum[i]=sum[i-1]+a[p[i]];
    tree.init(1,sz*4,sum);
    for(ll i=1;i<=sz;i++){
        if(m<=sz){
            ll sm=tree.query_Max(1,sz*4,i,i+m-1)-sum[i-1];
            ans=max(ans,sm);
        }
        else {
            if(sum[sz]<=0){
                ll sm=tree.query_Max(1,sz*4,i,i+(m%sz)+sz-1)-sum[i-1];
                ans=max(ans,sm);
            }
            else {
                ll sm=sum[sz]*((m/sz)-1)+tree.query_Max(1,sz*4,i,i+(m%sz)+sz-1)-sum[i-1];
                ans=max(ans,sm);
            }
        }
    }
}
int main(){
    ll t;
    scanf("%I64d",&t);
    for(ll cas=1;cas<=t;cas++){
        memset(vis,0,sizeof(vis));
        ans=0;
        scanf("%I64d%I64d%I64d%I64d",&n,&s,&m,&k);
        for(ll i=0;i<n;i++)
            scanf("%I64d",a+i);
        for(ll i=0;i<n;i++){
            if(!vis[i]){
                solve(i);
            }
        }
        printf("Case #%I64d: %I64d
",cas,max(0ll,s-ans));
    }
    return 0;
}

【倍增】

#include<bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second
#define debug(x) cerr<<#x<<" = "<<(x)<<endl
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int MAXN=(int)1e4+5;
const int MOD=(int)1e9+7;
struct node{
    ll a,b;
    node(){}
    node(ll x){
        b=x;
        a=max(x,0ll);
    }
    node operator + (const node &p)const{
            node re;
            re.b=b+p.b;
            re.a=max(a,b+p.a);
            return re;
    }
};
node a[MAXN][33];
int nxt[MAXN][33];
node cal(int x,int y){
    int k=0;
    node re=node(0);
    while(y){
        if(y&1){
            re=re+a[x][k];
            x=nxt[x][k];
        }
        k++;
        y>>=1;
    }
    return re;
}

int main()
{
    int t;
    scanf("%d",&t);
    for(int ca=1;ca<=t;ca++){
        int n,m,k;ll s;
        scanf("%d%lld%d%d",&n,&s,&m,&k);
        for(int i=0;i<n;i++){
            int x;
            scanf("%d",&x);
            a[i][0]=node(x);
            nxt[i][0]=(i+k)%n;
        }
        for(int j=1;(1<<j)<=m;j++){
            for(int i=0;i<n;i++){
                a[i][j]=a[i][j-1]+a[nxt[i][j-1]][j-1];
                nxt[i][j]=nxt[nxt[i][j-1]][j-1];
            }
        }
        ll ans=s;
        for(int i=0;i<n;i++){
            node tmp=cal(i,m);
            ans=min(ans,max(0ll,s-tmp.a));
        }
        printf("Case #%d: %lld
",ca,ans);
    }
    return 0;
}

【1009】

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5;
const ll mod = 1e9+7;
struct node
{
    int x,y,v,nxt;
}edge[maxn<<1];
ll head[maxn],cnt,n;
ll sz[maxn];
ll an;
int add(int x,int y,int v)
{
    edge[cnt].x=x;
    edge[cnt].y=y;
    edge[cnt].v=v;
    edge[cnt].nxt=head[x];
    head[x]=cnt++;
}
int dfs(int root,int fa)
{
    sz[root]=1;
    for(int i=head[root]; i!=-1; i=edge[i].nxt)
    {
        int a=edge[i].y;
        int b=edge[i].v;
        if(a==fa)   continue;
        dfs(a,root);
        sz[root] += sz[a];
        an = ( an + (n-sz[a])%mod * sz[a]%mod * b%mod )%mod;
    }
}
ll fac[maxn];
int main()
{
    while(~scanf("%d",&n))
    {
        fac[0]=1;
        for(int i=1;i<=maxn;i++)
            fac[i]=(fac[i-1]*i)%mod;//阶乘取余打表
        an=0;
        memset(head,-1,sizeof(head));
        memset(sz,0,sizeof(sz));
        cnt=0;
        for(int i=1;i<=n-1;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        }
        dfs(1,-1);
        printf("%lld
",(ll)(2*an%mod*fac[n-1]%mod)%mod);
    }
}

【1010】

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 1000000000;
const int maxn = 123456;
int T, n, m;
int tot, ans;
int maxs[maxn * 4];
struct Node
{
    int x, y;
    int val;
    int idd;
}nod[maxn];


int cmp1(Node a, Node b)
{
    if (a.y != b.y)
        return a.y<b.y;
    else
        return a.x<b.x;
}

int cmp2(Node a, Node b)
{
    if (a.x != b.x)
        return a.x<b.x;
    else
        return a.y>b.y;
}



void Pushup(int rt)
{
    maxs[rt] = max(maxs[rt * 2], maxs[rt * 2 + 1]);
}

void Build(int l, int r, int rt)
{
    if (l == r)
    {
        maxs[rt] = 0;
        return;
    }
    int m = (l + r) / 2;
    Build(l, m, rt * 2);
    Build(m + 1, r, rt * 2 + 1);
    Pushup(rt);
}

void Update(int pos, int l, int r, int k, int rt)
{
    if (l == r)
    {
        maxs[rt] = k;
        return;
    }
    int m = (l + r) / 2;
    if (pos <= m)
        Update(pos, l, m, k, rt * 2);
    else
        Update(pos, m + 1, r, k, rt * 2 + 1);
    Pushup(rt);
}

int QueryMax(int L, int R, int l, int r, int rt)
{
    if (R == 0)
        return 0;
    if (l >= L&&r <= R)
        return maxs[rt];
    int m = (l + r) / 2;
    int ret = -INF;
    if (L <= m)
        ret = max(ret, QueryMax(L, R, l, m, rt * 2));
    if (R>m)
        ret = max(ret, QueryMax(L, R, m + 1, r, rt * 2 + 1));
    return ret;
}

int main()
{
    scanf("%d", &T);
    while (T--)
    {
        ans = -INF;
        tot = 1;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
            scanf("%d%d%d", &nod[i].x, &nod[i].y, &nod[i].val);
        sort(nod + 1, nod + n + 1, cmp1);
        nod[1].idd = tot++;//离散化



        for (int i = 2; i <= n; i++)
        {
            if (nod[i].y == nod[i - 1].y)
                nod[i].idd = nod[i - 1].idd;
            else
                nod[i].idd = tot++;
        }

        sort(nod + 1, nod + n + 1, cmp2);
        Build(1, n, 1);
        for (int i = 1; i <= n; i++)
        {
            int x = QueryMax(1, nod[i].idd - 1, 1, n, 1);
            ans = max(x + nod[i].val, ans);
            Update(nod[i].idd, 1, n, x + nod[i].val, 1);
        }
        printf("%d
", ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Roni-i/p/9535151.html