2019-8-18 省赛选拔

A:训仓达人

      先状态压缩把每个区间特别的仓鼠表示出来,然后进行一次区间DP,在区间DP的顺带判断一下是否会不用花费就可以了.

AC_Code

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

const int maxn = 155;
const long long  inf = 1e18+7;
int n,m;
long long  val[155];
long long  f[155][155];
long long  b[150];
long long  dp[155][155];
long long  pre[155];
int main() {
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++) {
        scanf("%lld",&val[i]);
        pre[i+1] = pre[i] + val[i];
        b[i] = -1;
    }
    for(int i=0;i<m;i++) {
        int c;
        scanf("%d",&c);
        b[c-1] = i;
    }
    for(int len=1;len<=n;len++) {
        for(int i=0;i+len-1<n;i++) {
            int j = i+len -1;
            if(i == j) f[i][j] = (b[i] == -1? 0:(1<<b[i]));
            else {
                f[i][j] =(f[i][j-1]|f[j][j]);
            }
        }
    }
    for(int len = 1;len<=n;len++) {
        for(int i = 0;i+len-1<n;i++) {
            int j = i+len-1;
            if(i==j) {
                dp[i][j] = 0;
                continue;
            }
            else {
                dp[i][j] = inf;
            }
            for(int k=i;k<j;k++) {
                int s1 = f[i][k];
                int s2 = f[k+1][j];
                if(((s1<<1)&s2) || ((s1>>1)&s2)) {
                    //printf("%d %d %d??\n", i,j,k);
                    dp[i][j] = min(dp[i][k] + dp[k+1][j],dp[i][j]);
                }
                else {
                    dp[i][j] = min(dp[i][k] + dp[k+1][j] + pre[j+1] - pre[i],dp[i][j]);
                }
            }
        }
    }
    printf("%lld\n",dp[0][n-1]);
    return 0;
}
B: PUBG 1v3

      很简单的一道线段树,比赛的时候 p公子 直接给我口胡成计算几何,题意都没有告诉我…
      对于每个人能攻击的范围我们转化成一个矩阵,那么我们要的结果就是这个矩阵内的人数 - 自己队的人数,因为每队人数最多只有 4 个,我们完全可以先不管是否是本队的人(甚至包括他自己),等我们求出矩阵人数后直接暴力减去就可以了.
      对于矩阵内人数的求解,我们可以参照扫描线的思想,将这个矩阵转化成两个新的矩阵之差,这两个矩阵拥有同样的底边,如下图.
在这里插入图片描述
所以s1中的个数就是s1 +s2 中的个数 - s2 中的个数,由此我们可以联想到前缀和,所以我们用个线段树去存所有区间的前缀和情况,用线段树查询就可以了.

Ac_Code

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;

const int maxn = 1e6+7;

struct node
{
	int x,y,d,team,nex; 
}s[maxn];

struct Q
{
	int x1,x2,y,f;
	int id;
}deq[maxn<<2];

bool cmp(const Q& a,const Q& b) {
	return a.y<b.y;
}

bool cmp1(const int& a,const int& b) {
	return s[a].y<s[b].y;
}

int n,m,e;
int tr[(maxn+7)<<3];
int head[maxn];
int p[maxn];
int ans[maxn];
int end_ans[maxn];
void pushup(int num) {tr[num] = tr[num<<1] + tr[num<<1|1];}

void build(int l,int r,int num) {
	if(l==r) {
		tr[num] = 0;
		return ;
	}
	int mid =(l+r) >>1;
	build(l,mid,num<<1);
	build(mid+1,r,num<<1|1);
	pushup(num);
}

void modify(int l,int r,int num,int pos,int d) {
	if(l==r) {
		tr[num]+=d;
		return ;
	}
	int mid = (l+r) >>1;
	if(pos<=mid) modify(l,mid,num<<1,pos,d);
	if(mid< pos) modify(mid+1,r,num<<1|1,pos,d);
	pushup(num);
}

int quriy(int l,int r,int num,int le,int ri) {
	if(le<=l && r<= ri) return tr[num];
	int mid =(l+r) >>1;
	int ans =0;
	if(le<=mid) ans += quriy(l,mid,num<<1,le,ri);
	if(mid< ri) ans += quriy(mid+1,r,num<<1|1,le,ri);
	return ans;
}

int main() {
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) {
		scanf("%d%d%d%d",&s[i].x,&s[i].y,&s[i].d,&s[i].team);
		p[i] = i;
		s[i].x++;
		s[i].y++;
		s[i].nex = head[s[i].team];
		head[s[i].team] = i;
		deq[e].x1 = max(-maxn+1,s[i].x-s[i].d);
		deq[e].x2 = min(maxn-1,s[i].x+s[i].d);
		deq[e].y = max(-maxn+1,s[i].y - s[i].d)-1;
		deq[e].id = i;
		deq[e++].f = -1;
		deq[e].x1 = max(-maxn+1,s[i].x-s[i].d);
		deq[e].x2 = min(maxn-1,s[i].x+s[i].d);
		deq[e].y = min(maxn-1,s[i].y + s[i].d);
		deq[e].id = i;
		deq[e++].f = 1;
	}
	build(1,maxn*2,1);
	sort(deq,deq+e,cmp);
	sort(p+1,p+n+1,cmp1);
	int cnt = 1;
	for(int i=0;i<e;i++) {
		while(cnt<=n && s[p[cnt]].y <= deq[i].y) {
			modify(1,maxn*2,1,s[p[cnt]].x+maxn,1);
			cnt++;
			//cout<<cnt<<endl;
		}
		ans[deq[i].id] += deq[i].f * quriy(1,maxn*2,1,deq[i].x1+maxn,deq[i].x2+maxn);
 		//printf("%d %d %d?\n", deq[i].id,ans[deq[i].id],quriy(1,maxn,1,deq[i].x1,deq[i].x2));
 	}
 	for(int i = 1;i<=n;i++) {
 		int tea = s[i].team;
 		int x = s[i].x;
 		int y = s[i].y;
 		int d = s[i].d;
 		for(int j = head[tea];j;j=s[j].nex) {
		//cout<<"?"<<endl;
 			int xx = s[j].x;
 			int yy = s[j].y;
 			if(abs(xx-x) <= d  && abs(yy-y) <=d) ans[i]--;
 		}
 		end_ans[tea] = max(end_ans[tea],ans[i]);
 	}
 	int q;
 	scanf("%d",&q);
 	while(q--) {
 		int x;
 		scanf("%d",&x);
 		printf("%d\n", end_ans[x]);
 	}
	return 0;
}

C:简单计算题

      所有可能数 对 y取模一定只有 y种结果,那么我们只需要看 前y+1 个数 的取模情况,如果y+1个数内没有数模 y 为 0,那么说明 后面一定没有数。

AC_Code

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;

int B,x,y;

int main() {
	int t;
	scanf("%d",&t);
	while(t--) {
		scanf("%d%d%d",&B,&x,&y);
		int sum = 0;
		int ans = 0;
		do {
			ans++;
			sum = (sum*B+x)%y;
		}
		while(sum!=0 && ans <= (y+7));
		printf("%d\n",ans>y+7? -1:ans);
	}
	return 0;
}
D:简单题

      我们将边权分成均等的两部分,分给它连接的两个点,然后我们就成了选点问题,贪心即可,因为有奇数边权,我们先把所有值乘以 2,后面再除掉就可以了

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;

const int maxn = 1e4+7;

int n,m;
long long a[maxn];


int main() {
    scanf("%d%d",&n,&m);
    for(int i = 0;i<n;i++) {
        scanf("%lld",&a[i]);
        a[i] *= 2;
    }
    for(int i =0;i<m;i++) {
        int l,r,c;
        scanf("%d%d%d",&l,&r,&c);
        a[l-1] += c;
        a[r-1] += c;
    }
    sort(a,a+n);
    long long sum =0;
    int t=1;
    for(int i=n-1;i>=0;i--) {
    	//cout<<a[i]<<endl;
        sum += a[i]*t;
        t *= -1;
    }
    printf("%lld\n",sum/2);
    return 0;
}

F:轰炸区

      经典的矩阵快速幂+期望DP,可惜日天卡了浮点误差,一直过不了…

//附上标称
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<math.h>
#include<cstdlib>
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=(a)-1;i>=b;--i)
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fuck(x) cout<<'[' << #x << ' ' << x << ']' << endl;
using namespace std;
const int MX = 1e2 + 5;
const int MM = 22;
int N;
struct Mat {
    long double x[MM][MM];
    Mat() {memset (x, 0, sizeof (x) );}
    void init() {rep (i, 0, N) x[i][i] = 1;}
    void clr() {memset (x, 0, sizeof (x) );}
    Mat operator* (const Mat& _A) const {
        Mat ret;
        rep (i, 0, N) rep (j, 0, N) rep (k, 0, N) {
                    ret.x[i][j] += x[i][k] * _A.x[k][j];
                }
        return ret;
    }
} A, B;
int d[MX][MX], cnt[MM];
long double dp[MM], p[MM];
void pre_solve (int n) {
    N = 0;
    rep (i, 0, n) rep (j, 0, n) N = max (N, d[i][j] + 1);
    rep (i, 0, n) rep (j, 0, n) cnt[d[i][j]]++;
    rep (i, 0, N) p[i] = 1.0 * cnt[i] / (n * n);
    rep (i, 1, N) p[i] /= 1 - p[0];
    A.clr();
    rep (i, 1, N - 1) A.x[i][i - 1] = 1;
    A.x[N - 1][N - 1] = 1;
    rep (i, 1, N) A.x[0][i - 1] = 1.0 * p[i];
    A.x[0][N - 1] = 1;
    B.x[N - 1][0] = 1 / (1 - p[0]);
}
Mat power (int n) {
    Mat ret; ret.init();
    while (n) {
        if (n & 1) ret = ret * A;
        A = A * A;
        n >>= 1;
    }
    return ret;
}
double solve (int n, int m) {
    pre_solve (n);
    Mat ans = power (m) * B;
    return ans.x[0][0];
}
double solve() {
    int n, m;
    cin >> n >> m;
    rep (i, 0, n) rep (j, 0, n) cin >> d[i][j];
    return solve (n, m);
}
int main() {
    printf("%.3f\n", solve());
    return 0;
}
G:丢手绢

      每次暴力修改每两个数之和,用线段树维护最大值.
AC_Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<vector>
#include<cmath>
#include<bitset>
#include<cassert>
using namespace std;

const int maxn = 1e5+7;
const int inf = 2e9+7;

int n,k,m;
int a[maxn];
int pa[maxn][10];
int Max[maxn<<2];
int Min[maxn<<2];

void pushup(int num) {
    Max[num] = max(Max[num<<1],Max[num<<1|1]);
    Min[num] = min(Min[num<<1],Min[num<<1|1]);
}

void build(int l,int r,int num) {
    if( l==r ) {
        Max[num] = 0;
        Min[num] = inf;
        return ;
    }
    int mid = (l+r) >>1;
    build(l,mid,num<<1);
    build(mid+1,r,num<<1|1);
    pushup(num);
}

void modify(int l,int r,int num,int pos,int tmp,int op) {
    if(l==r) {
        if(op==1) Min[num] = tmp; 
        else Max[num] = tmp;
        return ; 
    }
    int mid = (l+r) >>1;
    if(pos<=mid) modify(l,mid,num<<1,pos,tmp,op);
    if(mid< pos) modify(mid+1,r,num<<1|1,pos,tmp,op);
    pushup(num);
}

int main() {
    scanf("%d",&n);
    for(int i=0;i<n;i++) {
        scanf("%d",&a[i]);
    }
    scanf("%d%d",&m,&k);
    build(1,n,1);
    for(int i=0;i<n;i++) {
        int mins=inf;
        int maxs=0;
        for(int j=1;j<=k;j++) {
            int l = (i+j)%n;
            pa[i][j] = a[i]+a[l];
            //cout<<pa[i][j]<<endl;
            mins = min(mins,pa[i][j]);
            maxs = max(maxs,pa[i][j]);
        }
        //cout<<i<<' '<<mins<<' '<<maxs<<endl;
        modify(1,n,1,i+1,mins,1);
        modify(1,n,1,i+1,maxs,2);
    }
    while(m--) {
        int op;
        scanf("%d",&op);
        if(op == 2) {
            printf("%d %d\n",Max[1],Min[1]);
        }
        else {
            int pos,x;
            scanf("%d%d",&pos,&x);
            a[pos-1] = x;
            for(int i=pos-1-k;i<=pos-1;i++) {
                int mins = inf;
                int maxs = 0;
                for(int j =1;j<=k;j++) {
                    int l = (i+j)%n;
                    pa[i][j] = a[i] + a[l];
                    mins = min(mins,pa[i][j]);
                    maxs = max(maxs,pa[i][j]);
                }
                modify(1,n,1,i+1,mins,1);
                modify(1,n,1,i+1,maxs,2);
            }
        }
    }
    return 0;
}
H:zhrt的数据结构课3

      对于题目所给的树,我们求出直径 和到根节点的最长链.
      最后结果等于 一棵树的直径 + (其他所有树最长链之和)*2,注意特判只有一个节点的树

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<vector>
#include<cmath>
#include<bitset>
#include<cassert>
using namespace std;
typedef long long LL;
LL INF = 1e18;
const LL maxn = 4e6 + 50;
LL ma[maxn], d[maxn];

struct Edge
{
    LL to, next;
} edge[maxn * 2];

LL k, head[maxn];

void add(LL a, LL b){
    edge[k].to = b;
    edge[k].next = head[a];
    head[a] = k++;
}

LL ins;

void dfs(LL u, LL pre, LL de){
    LL flag = 1;
    for(LL i = head[u]; i != -1; i = edge[i].next){
        LL to = edge[i].to;
        if(to == pre){
            continue;
        }
        flag = 0;
        dfs(to, u, de + 1);
    }
    if(flag){
        ma[ins] = max(ma[ins], de);
    }
}

queue<LL> que;
LL dis[maxn];
LL bfs1(LL s, LL num){
    for(LL i = 1; i <= num; i++){
        dis[i] = 0;
    }
    que.push(s);
    dis[s] = 1;
    LL MAX = 1;
    LL node = s;
    while(que.size()){
        LL u = que.front();
        que.pop();
        for(LL i = head[u]; i != -1; i = edge[i].next){
            LL to = edge[i].to;
            if(!dis[to]){
                dis[to] = dis[u] + 1;
                if(dis[to] > MAX){
                    node = to;
                    MAX = dis[to];
                }
                que.push(to);
            }
        }
    }
    return node;
}

LL bfs2(LL s, LL num){
    for(LL i = 1; i <= num; i++){
        dis[i] = 0;
    }
    que.push(s);
    dis[s] = 1;
    LL MAX = 1;
    while(que.size()){
        LL u = que.front();
        que.pop();
        for(LL i = head[u]; i != -1; i = edge[i].next){
            LL to = edge[i].to;
            if(!dis[to]){
                dis[to] = dis[u] + 1;
                //printf("u = %lld dis[%lld] = %lld\n", u, to, dis[to]);
                if(dis[to] > MAX){
                    MAX = dis[to];
                }
                que.push(to);
            }
        }
    }
    return MAX - 1;
}
int main() {
    LL n;
    scanf("%lld", &n);
    LL maans = 0, mians = INF;
    LL sum = 0;
    int cnt = 0;
    for(LL j = 1; j <= n; j++){
        //prLLf("999\n");
        ins++;
        LL num;
        scanf("%lld", &num);
        k = 0;
        for(LL i = 1; i <= num; i++){
            head[i] = -1;
        }
        LL root;
        for(LL i = 1; i <= num; i++){
            LL x;
            scanf("%lld", &x);
            if(x == 0){
                root = i;
            } else{
                add(x, i);
                add(i, x);
            }
        }
        dfs(root, 0, 0);
        LL node = bfs1(root, num);
        d[j] = bfs2(node, num);
        sum += ma[j] * 2;
        if(ma[j] == 0){
            cnt++;
            continue;
        }
        mians = min(ma[j] * 2 - d[j], mians);
        maans = max(ma[j] * 2 - d[j], maans);
    }
    if(cnt == n){
        printf("0 0\n");
    } else{
        printf("%lld %lld\n", sum - mians, sum - maans);
    }
    return 0;
}

G:本场最简单签到题

      最终结果爆ull,我们需要自己写个输出

Ac_Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<vector>
#include<cmath>
#include<bitset>
#include<cassert>
using namespace std;
struct node
{
    int a;
    unsigned long long  b;
} s[200005];
unsigned long long   g[1000005];
bool  vis[1000006];
int ans[70];
void getans(unsigned long long a,unsigned long long b,unsigned long long c) {
    int d = 0;
    for(int i = 65;i>=0;i--) {
        ans[i] = (a%10 + b%10 + c%10 + d);
        d = ans[i]/10;
        ans[i] %= 10;
        a/= 10;
        b /= 10;
        c/=10;
    }
    int flag = 0;
    for(int i=0;i<66;i++) {
        if(flag == 0 && ans[i] == 0) continue;
        else if(flag == 0 && ans[i] != 0) {
            flag = 1;
            printf("%d",ans[i]);
        }
        else printf("%d",ans[i]);
    }
    if(flag == 0) printf("0\n");
    else printf("\n");
}
int main() {
    int t;
    scanf("%d",&t);
    while (t--)
    {
        memset(g,0,sizeof(g));
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; ++i)
        {
            scanf("%d",&s[i].a);
        }
        for (int i = 0; i < n; ++i)
        {
            scanf("%lld",&s[i].b);
        }
        int max1=0;
        for (int i = 0; i < n; ++i)
        {
            if(g[s[i].a] == 0){{
                g[s[i].a] = s[i].b;
                max1=max(max1,s[i].a);
            }
            } else{
                g[s[i].a] = min(s[i].b, g[s[i].a]);
            }
        }
        int ans = 0;
        for(int i=0;i<=max1;++i)
        {
            if (g[i]>0){
                ans++;
            }
        }
        if (ans<=2)
        {
            printf("-1\n");
            continue;
        }
        unsigned long long   min1,min2,min3;
        min1=min2=min3=9223372036854775807;
        for(int i=0;i<=max1;++i)
        {
            if (g[i]>0)
            {
                if (g[i]<min1)
                {
                    min3=min2;
                    min2=min1;
                    min1=g[i];
                }else if (g[i]>=min1&&g[i]<min2)
                {
                    min3=min2;
                    min2=g[i];
                }
                else if (g[i]>=min2&&g[i]<min3)
                {
                    min3=g[i];
                }
            }
        }
       //cout<<min1<<" "<<min2<<" "<<min3<<endl;
        getans(min1,min2,min3);
    }
    return 0;
}
J:一个顶俩

      对于每条备用边找这个边对应两个点的LCA,当碰到这个点的时候这条边就成了无用边.
然后树形DP即可.

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<vector>
#include<cmath>
#include<bitset>
#include<cassert>
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
#define mme(a,b) memset((a),(b),sizeof((a)))
#define fuck(x) cout<<"* "<<x<<"\n"
using namespace std;
typedef pair<int, int> pii;
typedef  long long LL;
const int maxn =1e5+7;

int n,m,q,e,cnt;
int head[maxn];
int edge[maxn<<2];
int nex[maxn<<2];
int vis[maxn<<2];
int le[maxn],ri[maxn];

void add1(int l,int r) {
    edge[++e] = r;
    nex[e] = head[l];
    head[l] = e;
}


int son[maxn],sz[maxn],dep[maxn],top[maxn],fath[maxn];
int tod[maxn];
int del[maxn];

int dfs1(int u,int f) {
    dep[u] = dep[f]+1;
    sz[u]=1;
    for(int i=head[u];i;i=nex[i]) {
        int v = edge[i];
        if(v==f) continue;
        sz[u]+=dfs1(v,u);
        if(sz[v] > sz[son[u]]) son[u]=v;
    }
    return sz[u];
}

int dfs2(int u,int f,int up) {
    // cout<<u<<' '<<f<<' '<<up<<endl;
    le[u] = ri[u] = ++cnt;
    fath[u] = f;
    top[u] = up;
    if(son[u]) ri[u] = dfs2(son[u],u,up);
    for(int i=head[u];i;i=nex[i]) {
        int v=edge[i];
        if(v==f||v==son[u]) continue;
        ri[u] = dfs2(v,u,v);
    }
    return ri[u];
}

int lca(int u,int v) {
    while(top[u]!=top[v]) {
        // cout<<top[u]<<'!'<<top[v]<<endl;
        if(dep[top[u]] >= dep[top[v]]) {
            u = fath[top[u]];
        }
        else {
            v = fath[top[v]];
        }
    }
    if(dep[u] >= dep[v]) return v;
    else return u;
}

int dp[maxn];
void getans(int u,int f) {
    dp[u] = tod[u]-2*del[u];
    for(int i = head[u];i;i=nex[i]) {
        int v = edge[i];
        if( v==f ) continue;
        getans(v,u);
        dp[u]+= dp[v];
    }
    return ;
}

int main() {
    scanf("%d%d%d",&n,&m,&q);
    for(int i = 0;i<n-1;i++) {
        int l,r;
        scanf("%d%d",&l,&r);
        add1(l,r);
        add1(r,l);
    }
    dfs1(1,0);
    dfs2(1,0,1);
    for(int i=0;i<m;i++) {
        int l,r;
        scanf("%d%d",&l,&r);
        tod[l]++;
        tod[r]++;
        int c = lca(l,r);
        del[c]++;
    }
    getans(1,0);
    while(q--) {
        int num;
        scanf("%d",&num);
        int l = edge[num*2];
        int r = edge[num*2-1];
        if(dep[l] > dep[r] ) printf("%d\n",dp[l]);
        else printf("%d\n",dp[r]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值