zoukankan      html  css  js  c++  java
  • 2020JSCPC补题

    过了4题,铜牌qwq

    补题花了挺长时间

    A Array

    比赛的时候写了个加标记,乘标记,次方标记,麻烦死,最后写到比赛结束也没写完QAQ

    太难顶了

    比赛结束后才把这看成是一个映射

    这题也反应出了我对懒标记的不熟悉

    补这题前复习了线段树,并大改了自己的线段树模板。

    补完这题后,又计时默写了几次线段树模板,现在能15min内默写出线段树加标记+乘标记的模板了

    思路:关键的一点就是注意到模数非常小,我们记录每个节点上有多少个数取膜后为某一值,用一个数组来存这个个数

    比如用zz[x]表示这个区间上取膜后为x的数有zz[x]个

    区间加、乘、次方实际上都是对这个数组进行了映射操作

    所以我们就用一个结构体为映射的懒标记

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    const int MAXN = 1e5 + 7;
    int a[MAXN];
    int n, p, q;
    int k;
    int qpow(int a, int b) {
        int res = 1;
        for (; b; a = a * a % p) {
            if (b & 1) res = res * a % p;
            b >>= 1;
        }
        return res;
    }
    struct F {
        int pt[30];
    };
    struct NODE {
        int l, r, mid, len;
        bool ff;//懒标记
        int zz[30];
        F f;//懒标记
        NODE* lson;
        NODE* rson;
    };
    NODE* head = new(NODE);
    void upd(NODE* pp) {
        for (int i = 0; i < p; i++) {
            pp->zz[i] = pp->lson->zz[i] + pp->rson->zz[i];
        }
    }
    void build(NODE* pp, int l, int r) {
        pp->l = l; pp->r = r; pp->mid = l + r >> 1; pp->len = r - l + 1; pp->lson = new(NODE); pp->rson = new(NODE);
        for (int i = 0; i < p; i++) pp->f.pt[i] = i;
        pp->ff = false;
        if (l == r) {
            for (int i = 0; i < p; i++) pp->zz[i] = 0;
            int x;
            scanf("%d", &x);
            x %= p;
            pp->zz[x]++;
            return;
        }
        int mid = pp->mid;
        build(pp->lson, l, mid);
        build(pp->rson, mid + 1, r);
        upd(pp);
    }
    void pd(NODE* pp) {
        if (pp->l == pp->r) return;
        pp->lson->ff = true; pp->rson->ff = true;
        int tmp[30] = { 0 };
        for (int i = 0; i < p; i++) {
            pp->lson->f.pt[i] = pp->f.pt[pp->lson->f.pt[i]];
            pp->rson->f.pt[i] = pp->f.pt[pp->rson->f.pt[i]];
        }
        for (int i = 0; i < p; i++) {
            tmp[pp->f.pt[i]] += pp->lson->zz[i];
        }
        for (int i = 0; i < p; i++) {
            pp->lson->zz[i] = tmp[i];
            tmp[i] = 0;
        }
        for (int i = 0; i < p; i++) {
            tmp[pp->f.pt[i]] += pp->rson->zz[i];
        }
        for (int i = 0; i < p; i++) {
            pp->rson->zz[i] = tmp[i];
        }
        pp->ff = false;
        for (int i = 0; i < p; i++) pp->f.pt[i] = i;
    }
    void CHANGE(NODE* pp, int l, int r, F f) {
        if (pp->l == l && pp->r == r) {
            pp->ff = true;
            int tmp[30] = { 0 };
            for (int i = 0; i < p; i++) {
                pp->f.pt[i] = f.pt[pp->f.pt[i]];
                tmp[f.pt[i]] += pp->zz[i];
            }
            for (int i = 0; i < p; i++) pp->zz[i] = tmp[i];
            return;
        }
        if(pp->ff) pd(pp);
        int mid = pp->mid;
        if (r <= mid) CHANGE(pp->lson, l, r, f);
        else if (l > mid) CHANGE(pp->rson, l, r, f);
        else {
            CHANGE(pp->lson, l, mid, f);
            CHANGE(pp->rson, mid + 1, r, f);
        }
        upd(pp);
    }
    int sc[30];
    void Q(NODE* pp, int l, int r) {
        if (pp->l == l && pp->r == r) {
            for (int i = 0; i < p; i++) {
                sc[i] += pp->zz[i];
            }
            return;
        }
        if (pp->ff) pd(pp);
        int mid = pp->mid;
        if (r <= mid)Q(pp->lson, l, r);
        else if (l > mid) Q(pp->rson, l, r);
        else {
            Q(pp->lson, l, mid);
            Q(pp->rson, mid + 1, r);
        }
    }
    int main()
    {
        cin >> n >> p;
        build(head, 1, n);
        cin >> q;
        int op, l, r;
        for (int e = 1; e <= q; e++) {
            scanf("%d", &op);
            if (op == 1) {
                scanf("%d%d%d", &l, &r, &k);
                F f;
                for (int i = 0; i < p; i++) {
                    f.pt[i] = (i + k) % p;
                }
                CHANGE(head, l, r, f);
            }
            else if (op == 2) {
                scanf("%d%d%d", &l, &r, &k);
                F f;
                k %= p;
                for (int i = 0; i < p; i++) {
                    f.pt[i] = (i * k) % p;
                }
                CHANGE(head, l, r, f);
            }
            else if (op == 3) {
                scanf("%d%d%d", &l, &r, &k);
                F f;
                for (int i = 0; i < p; i++) {
                    f.pt[i] = qpow(i, k);
                }
                CHANGE(head, l, r, f);
            }
            else if (op == 4) {
                scanf("%d%d%d", &l, &r, &k);
                for (int i = 0; i < p; i++) sc[i] = 0;
                Q(head, l, r);
                int ans = 0, res = 0;
                for (int i = 0; i < p; i++) {
                    res = qpow(i, k);
                    ans += res * sc[i];
                    ans %= p;
                }
                printf("%d
    ", ans);
            }
            else if (op == 5) {
                scanf("%d%d%d", &l, &r, &k);
                for (int i = 0; i < p; i++) sc[i] = 0;
                Q(head, l, r);
                int ans = 1, res = 0;
                for (int i = 0; i < p; i++) {
                    res = qpow(i, sc[i]);
                    ans = ans * res % p;
                }
                printf("%d
    ", ans);
            }
        }
        return 0;
    }
    

      

    I Intersections

    这题比A题简单,比赛时应该开这题的qwq

    就是一个最短路   (趴)

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<queue>
    #include<vector>
    using namespace std;
    const int MAXN = 3e5;
    const long long INF = (long long)1<<60;
    int n,m,xs,ys,xt,yt;
    long long a[MAXN],b[MAXN],c[MAXN],w[MAXN],dis[MAXN];
    void dijkstra(int st){
    	priority_queue<pair<long long,int>,vector<pair<long long ,int> >,greater<pair<long long,int> > > que;
    	dis[st] = 0;
    	que.push(make_pair(dis[st],st));
    	while(!que.empty()){
    		int node = que.top().second;
    		long long dt = que.top().first;
    		if(dis[node]<dt){
    			que.pop();
    			continue;
    		}
    		que.pop();
    		long long k = dis[node] / (a[node] + b[node]);
    		long long re = dis[node] - k * (a[node] + b[node]);
    		if(re<a[node]){
    			long long ad = a[node] - re;
    			int po = node - m;
    			if(po > 0 && dis[po] > dis[node] + w[po]){
    				dis[po] = dis[node] + w[po];
    				que.push(make_pair(dis[po],po));
    			}
    			po = node + m;
    			if(po <= n*m && dis[po] > dis[node] + w[node]){
    				dis[po] = dis[node] + w[node];
    				que.push(make_pair(dis[po],po));
    			}
    			if(node % m){
    				po = node + 1;
    				if(dis[po] > dis[node] + ad + c[node]){
    					dis[po] = dis[node] + ad + c[node];
    					que.push(make_pair(dis[po],po));
    				}
    			}
    			if(node % m != 1){
    				po = node - 1;
    				if(dis[po] > dis[node] + ad + c[po]){
    					dis[po] = dis[node] + ad + c[po];
    					que.push(make_pair(dis[po],po));
    				}
    			}
    		}
    		else{
    			int po = node - m;
    			if(po > 0 && dis[po] > (k+1) * (a[node] + b[node]) + w[po] ){
    				dis[po] = (k+1) * (a[node] + b[node]) + w[po];
    				que.push(make_pair(dis[po],po)); 
    			}
    			po = node + m;
    			if(po <= n*m && dis[po] > (k+1) * (a[node] + b[node]) + w[node]){
    				dis[po] = (k+1) * (a[node] + b[node]) + w[node];
    				que.push(make_pair(dis[po],po));
    			}
    			if(node % m){
    				po = node + 1;
    				if(dis[po] > dis[node] + c[node]){
    					dis[po] = dis[node] + c[node];
    					que.push(make_pair(dis[po],po));
    				}
    			}
    			if(node % m != 1){
    				po = node - 1;
    				if(dis[po] > dis[node] + c[po]){
    					dis[po] = dis[node] + c[po];
    					que.push(make_pair(dis[po],po));
    				}
    			}
    		}
    	}
    }
    int main()
    {
    	cin>>n>>m>>xs>>ys>>xt>>yt;
    	int id = 0;
    	for(int i = 1;i <= n;i++){
    		for(int j = 1;j <= m;j++){
    			id++;
    			scanf("%lld",&a[id]);
    			dis[id] = INF;
    		}
    	}
    	id = 0;
    	for(int i = 1;i <= n;i++){
    		for(int j = 1;j <= m;j++){
    			id++;
    			scanf("%lld",&b[id]);
    		}
    	}
    	id = 0;
    	for(int i = 1;i <= n;i++){
    		for(int j = 1;j <= m - 1;j++){
    			id++;
    			scanf("%lld",&c[id]);
    		}
    		c[++id] = 0; 
    	}
    	id = 0;
    	for(int i = 1;i <= n - 1;i++){
    		for(int j = 1;j <= m;j++){
    			id++;
    			scanf("%lld",&w[id]);
    		}
    	}
    	for(int j = 1;j <= m;j++) w[++id] = 0;
    	dijkstra((xs - 1) * m + ys);
    	cout<<dis[(xt - 1) * m + yt]<<endl;
    	return 0;
    }
    

      

    E Eliminate the Virus

    很有意思的一题

    思路:n <= 16,要想到用状态来表示,算出每个状态(st1)模拟一遍感染后得到的新状态 (st2),f [st1] = st2,

    注:f 是一个单值映射,但 f 的反函数不一定是单值函数,所以不要利用 f 的反函数

    题目虽然没说要最小步数,但步数也是有限制的,所以最好求最小步数

    这里状态不能从小到大遍历,因为有些状态可能是由比它大的状态转移过来

    所以我们就用bfs,从最大状态bfs,求出到各个状态的距离,如果dis[0]!=INF,说明存在答案

    接下来的这步就是求答案了

    求答案不能慌,再写一段来求答案,不能急于求成

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int INF = 1e6;
    const int MAXZT = 1 << 16;
    int f[MAXZT + 10];
    int cnt[MAXZT + 10];
    int graph[18][18];
    int ans[MAXZT + 10];
    int dis[MAXZT + 10];
    int pre[MAXZT + 10];
    bool vis[MAXZT + 10] = {false};
    int n, m, k;
    void init() {
    	bool b[18] = { false };
    	for (int st = 0; st < 1 << n; st++) {
    		dis[st] = INF;
    		pre[st] = -1;
    		vis[st] = false;
    		for (int i = 0; i < n; i++) b[i] = false;
    		for (int i = 0; i < n; i++) {
    			if (st & (1 << i)) {
    				for (int j = 1; j <= n; j++) {
    					if (graph[i + 1][j]) b[j - 1] = true;
    				}
    			}
    		}
    		int res = 0;
    		for (int i = 0; i < n; i++) {
    			if (b[i]) res += 1 << i;
    		}
    		f[st] = res;
    		int st2 = st;
    		while (st2) {
    			if (st2 & 1) cnt[st] ++;
    			st2 >>= 1;
    		}
    	}
    }
    void bfs(int st) {
    	queue<int>que;
    	que.push(st);
    	vis[st] = true;
    	dis[st] = 0;
    	while (!que.empty()) {
    		st = que.front();
    		que.pop();
    		for (int st2 = st; ; st2--, st2 &= st) {//遍历子集
    			if (cnt[st ^ st2] <= k) {
    				if (!vis[f[st2]]) {
    					dis[f[st2]] = dis[st] + 1;
    					pre[f[st2]] = st;
    					vis[f[st2]] = true;
    					que.push(f[st2]);
    				}
    			}
    			if (st2 == 0) break;
    		}
    	}
    }
    int main()
    {
    	cin >> n >> m >> k;
    	int u, v;
    	for (int i = 1; i <= n; i++)
    		for (int j = 1; j <= n; j++)
    			graph[i][j] = 0;
    	for (int i = 1; i <= m; i++) {
    		cin >> u >> v;
    		graph[u][v] = graph[v][u] = 1;
    	}
    	init();
    	int max_st = (1 << n) - 1;
    	bfs(max_st);
    	if (dis[0] == INF) {
    		cout << -1 << endl;
    		return 0;
    	}
    	cout << dis[0] << endl;
    	for (int tt = 0; tt != max_st;) {//找答案
    		int pp = pre[tt];
    		for (int st2 = pp; ; st2--, st2 &= pp) {//遍历子集
    			if (cnt[pp ^ st2] <= k) {
    				if (f[st2] == tt) {
    					ans[pp] = pp ^ st2;
    					break;
    				}
    			}
    			if (st2 == 0) break;
    		}
    		tt = pp;
    	}
    	int pos = 0;
    	for (int e = 1; e <= dis[0];e++) {
    		pos = pre[pos];
    		for (int i = 0; i < n; i++) {
    			if (ans[pos] & (1 << i)) {
    				printf("%c", 'a' + i);
    			}
    		}
    		printf("
    ");
    	}
    	return 0;
    } 
    

      

    G Grid Coloring

    一个星期才A这题,难顶

    这题原来是结论题,难的一匹,看了题解才会这题,原来是有规律的

    刚学矩阵加速,就来做这题,然后一直wa,我写了个暴力来对拍,然后发现前面几项对拍都一样,从某项开始就不一样了,

    于是我一直在debug我的矩阵,还是不能一样

    后来我又写了一个暴力+剪枝的对拍,发现原来是我之前的暴力答案错了。。我一直以为我的矩阵错了,调死调不出来

    既然矩阵没错,哪里wa了呢,我又继续对拍,然后发现,原来是n >= 5写成了n == 5了草。。。

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<vector> 
    using namespace std;
    const long long MOD = 1e9+7;
    const int MAXN = 103;
    int ST[100];
    struct Martix {
        int n;
        long long mat[MAXN][MAXN];
    
        void init() {
            memset(mat, 0, sizeof(mat));
        }
    
        void E_init() {
            memset(mat, 0, sizeof(mat));
            for (int i = 1; i <= n; i++) mat[i][i] = (long long)1;
        }
    
        void scan() {
            for (int i = 1; i <= n; i++)
                for (int j = 1; j <= n; j++)
                    scanf("%lld", &mat[i][j]);
        }
    
        void print() {
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= n; j++) cout << mat[i][j] << " ";
                cout << endl;
            }
        }
    
        Martix operator *(Martix b) {
            Martix tmp;
            tmp.init();
            tmp.n = n;
            for (int i = 1; i <= n; i++)
                for (int j = 1; j <= n; j++)
                    for (int k = 1; k <= n; k++) {
                        tmp.mat[i][j] += (mat[i][k] * b.mat[k][j]);
                        tmp.mat[i][j] = (MOD + tmp.mat[i][j] % MOD) % MOD;
                    }
            return tmp;
        }
    
    };
    Martix Mat_qpow(Martix A, long long k) {
        Martix ret;
        ret.n = A.n;
        ret.E_init();
        for (; k; k >>= 1, A = A * A){
            if (k & 1) ret = ret * A;
        }
        return ret;
    }
    int n,m;
    bool check(int st,int n){
    	int a[4],b[4];
    	for(int i = 1;i <= n ;i++){
    		if(st&1) b[n-i+1] = 1;
    		else b[n-i+1] = 0;
    		st>>=1;
    	} 
    	if(n == 3 && b[1] == b[2] && b[2] == b[3]) return false;
    	for(int i = 1;i <= n;i++){
    		if(st&1) a[n-i+1] = 1;
    		else a[n-i+1] = 0;
    		st>>=1;
    	}
    	if(n == 3 && a[1] == a[2] && a[2] == a[3]) return false;
    	return true;
    }
    bool ok(int st1,int st2,int n){
    	int a[4],b[4],c[4],d[4];
    	for(int i = 1;i <= n ;i++){
    		if(st1&1) b[n-i+1] = 1;
    		else b[n-i+1] = 0;
    		st1>>=1;
    	} 
    	if(n == 3 && b[1] == b[2] && b[2] == b[3]) return false;
    	for(int i = 1;i <= n;i++){
    		if(st1&1) a[n-i+1] = 1;
    		else a[n-i+1] = 0;
    		st1>>=1;
    	}
    	if(n == 3 && a[1] == a[2] && a[2] == a[3]) return false;
    	for(int i = 1;i <= n;i++){
    		if(st2&1) d[n-i+1] = 1;
    		else d[n-i+1] = 0;
    		st2>>=1;
    	} 
    	if(n == 3 && d[1] == d[2] && d[2] == d[3]) return false;
    	for(int i = 1;i <= n;i++){
    		if(st2&1) c[n-i+1] = 1;
    		else c[n-i+1] = 0;
    		st2>>=1;
    	}
    	if(n == 3 && c[1] == c[2] && c[2] == c[3]) return false;
    	for(int i = 1;i <= n;i++) 
    		if(b[i]!=c[i]) return false;
    	for(int i = 1;i <= n;i++){
    		if(a[i] == b[i] && b[i] == d[i]) return false;
    	}
    	if(n == 3 && a[1] == b[2] && c[2] == d[3]) return false;
    	if(n == 3 && a[3] == b[2] && c[2] == d[1]) return false;
    	return true;
    }
    int main()
    {
    	int T;
    	cin>>T;
    	while(T--){
    		cin>>n>>m;
    		if(n>m) swap(n,m);
    		if(n==1&&m==1){
    			cout<<2<<endl;
    			continue;
    		}
    		if(n==4&&m==4){
    			cout<<18<<endl;
    			continue;
    		}
    		if(n==4) {
    			cout<<14<<endl;
    			continue;
    		}
    		if(n>=5) {//写成n==5了啊啊啊啊啊啊啊啊 
    			cout<<8<<endl;
    			continue;
    		}
    		if(n<=3){
    			Martix A,B;
    			int tot = 0;
    			for(int st = 0;st < 1<<n*2;st++){
    					if(check(st,n)) ST[++tot] = st;
    			}
    			A.n = B.n = tot + 1;
    			A.init();B.init();
    			for(int i = 1;i <= tot;i++){
    				for(int j = 1;j <= tot;j++){
    					if(ok(ST[j],ST[i],n)){
    						A.mat[i][j] = (long long)1;
    					}
    				}
    			}
    			B = Mat_qpow(A,(long long)m-(long long)2);
    			Martix C;
    			C.n = tot + 1;
    			C.init();
    			for(int i = 1;i<=tot;i++) C.mat[i][1] = (long long)1;
    			B = B * C;
    			long long ans = 0;
    			for(int i = 1;i<=tot;i++) {
    				ans += B.mat[i][1];
    				ans %= MOD;
    			}
    			cout << ans << endl;
    		}		
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    jira 解决结果配置
    .net core ef mysql in 参数化写法
    CentOS安装破解版Jira 亲测有效(附带破解包)
    实现js读取Excel数据
    android权限(permission)大全
    如何搭建Nuget服务器
    WebApi配置Swagger
    Aps.Net WebApi依赖注入
    解决.Net Core跨域问题
    一篇关于Asp.Net Model验证响应消息的问题处理
  • 原文地址:https://www.cnblogs.com/ruanbaitql/p/14120492.html
Copyright © 2011-2022 走看看