zoukankan      html  css  js  c++  java
  • P4145 上帝造题的七分钟2 / 花神游历各国

    P4145 上帝造题的七分钟2 / 花神游历各国

    题目

    传送门

    思路

    听说直接暴力处理每一次更改+树状数组查询+小优化就能过这道题?!

    emm

    我是为了练分块才找到这道题的,所以自然是用分块啦

    首先,要明白,1e12最多也就是进行6次开平方操作就能变成1(详见下:源自程序计算)

    1000000000000
    1000000
    1000
    31
    5
    2
    1
    1
    

    我们设a[i][j]表示原输入数列中的第i个数进行j次开平方后得到的数,因此,当j为0时,就是原来的数列

    按老规矩定义int L[max_t] , R[max_t];int pos[nn];,不会的去分块模板

    另外定义int upd[i]表示第i个块整体开平方的次数

    查询

    对于每一次查询(不再赘述,直接看代码):

    ll query(rr int l , rr int r) {
    	rr int p = pos[l] , q = pos[r];
    	rr ll ans = 0;
    	if(p == q) {//l,r属于同一个块
    		for(int i = l ; i <= r ; ++i)
    			ans += a[i][upd[p]];
    		return ans;
    	}
    	for(rr int i = l ; i <= R[p] ; ++i)//开头
    		ans += a[i][upd[p]];
    	
    	for(rr int i = p + 1 ; i <= q - 1 ; ++i)//中间
    		ans += sum[i][upd[i]];
    	
    	for(rr int i = L[q] ; i <= r ; ++i)//结尾
    		ans += a[i][upd[q]];
    	
    	return ans;
    }
    

    修改

    然后对于每一次修改:

    void change_(int l , int r , int p) {//暴力修改第p个块暴力将[l,r]的数开平方
    	if(upd[p] == 7)return;//小优化,等下讲
    	for(int i = l ; i <= r ; ++i)
    		for(int j = 0 ; j <= 6 ; ++j)
    			a[i][j] = a[i][j + 1];
    	for(int j = 0 ; j <= 7 ; ++j) {//更新sum[p]
    		sum[p][j] = 0;
    		for(int i = L[p] ; i <= R[p] ; ++i)
    			sum[p][j] += a[i][j];
    	}
    }
    void change(int l , int r) {
    	if(cnt <= 0)return;
    	int p = pos[l] , q = pos[r];
    	if(p == q) {//l,r属于同一个块
    		change_(l , r , p);
    		return;
    	}
    	change_(l , R[p] , p);//开头一段
    	for(int i = p + 1 ; i <= q - 1 ; ++i)//中间
    		if(upd[i] < 7)++upd[i],--cnt;
    	change_(L[q] , r , q);//结尾
    	
    }
    

    优化

    结果发现,交上去是50分(TLE)

    我们的时间效率为 (O(nsqrt n)) 大概在1e7~1e8左右,但是前面带一个"7"的常数,再加上一丢丢小优化理论上是可以过的

    先是卡了一波常数,i++变为++i,变量尽量带上register,快速输出,然鹅也没有快多少

    考虑到每个数进行6次开方后再开方就无意义了,所以就有了上面见到的优化:if(upd[p] == 7)return;(在void change_(int l , int r , int p)中),然后就AC了,学校的老人机也能在200ms的时间下通过单个测试数据(原2000ms)

    代码(含对拍)

    对拍的命名按照老规矩(见前2篇博客)

    AC代码

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <cstring>
    #define ll long long
    #define nn 100010
    #define max_t 1010
    #define rr register
    //#pragma GCC optimize(3)
    using namespace std;
    long long read() {
    	long long re = 0;
    	char c = getchar();
    	
    	while(c < '0' || c > '9')c = getchar();
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0',
    		c = getchar();
    	return re;
    }
    int n , m , t;
    ll a[nn][15];
    ll sum[max_t][15];
    int L[max_t] , R[max_t];
    int upd[max_t];
    int pos[nn];
    int cnt;//cnt也是用于优化,但是已经有"思路"中的优化的情况下效果并不明显(O2优化下总时间快40ms(洛谷))
    void Init() {
    	memset(upd , 0 , sizeof(upd));
    	for(int i = 1 ; i <= n ; ++i)
    		for(int j = 1 ; j <= 7 ; ++j)
    			a[i][j] = (int)sqrt(a[i][j - 1]);
    	
    	t = sqrt(n);
    	int len = t;
    	R[0] = 0;
    	for(int i = 1 ; i <= t ; ++i)
    		L[i] = R[i - 1] + 1 , R[i] = i * len;
    	if(R[t] < n)
    		++t , L[t] = R[t - 1] + 1 , R[t] = n;
    	cnt = t * 7;
    	for(int i = 1 ; i <= t ; ++i)
    		for(int j = L[i] ; j <= R[i] ; ++j)
    			pos[j] = i;
    	
    	for(int i = 1 ; i <= t ; ++i)
    		for(int j = 0 ; j <= 7 ; ++j)
    			for(int k = L[i] ; k <= R[i] ; ++k)
    				sum[i][j] += a[k][j]; 
    }
    void change_(int l , int r , int p) {
    	if(upd[p] == 7)return;//注意这里的优化,挺重要的,学校的台式机(lao ren ji)测极限数据可从2000ms优化到200ms
    	for(int i = l ; i <= r ; ++i)
    		for(int j = 0 ; j <= 6 ; ++j)
    			a[i][j] = a[i][j + 1];
    	for(int j = 0 ; j <= 7 ; ++j) {
    		sum[p][j] = 0;
    		for(int i = L[p] ; i <= R[p] ; ++i)
    			sum[p][j] += a[i][j];
    	}
    }
    void change(int l , int r) {
    	if(cnt <= 0)return;
    	int p = pos[l] , q = pos[r];
    	if(p == q) {
    		change_(l , r , p);
    		return;
    	}
    	change_(l , R[p] , p);
    	for(int i = p + 1 ; i <= q - 1 ; ++i)
    		if(upd[i] < 7)++upd[i],--cnt;
    	change_(L[q] , r , q);
    	
    }
    ll query(rr int l , rr int r) {
    	rr int p = pos[l] , q = pos[r];
    	rr ll ans = 0;
    	if(p == q) {
    		for(int i = l ; i <= r ; ++i)
    			ans += a[i][upd[p]];
    		return ans;
    	}
    	for(rr int i = l ; i <= R[p] ; ++i)
    		ans += a[i][upd[p]];
    	
    	for(rr int i = p + 1 ; i <= q - 1 ; ++i)
    		ans += sum[i][upd[i]];
    	
    	for(rr int i = L[q] ; i <= r ; ++i)
    		ans += a[i][upd[q]];
    	
    	return ans;
    }
    void output(ll x) {
    	if(x >= 10)output(x / 10);
    	putchar(x % 10 + '0');
    }
    int main() {
    	n = read();
    	for(rr int i = 1 ; i <= n ; i++)
    		a[i][0] = read();
    	Init();
    	m = read();
    	for(int i = 1 ; i <= m ; ++i)  {
    		int op = read() , l = read() , r = read();
    		if(l > r){rr int tmp = l ; l = r ; r = tmp;}
    		if(op == 0)	change(l , r);
    		else {
    			/*
    			printf("%lld
    " , query(l , r));
    			/*/
    			output(query(l , r));
    			putchar('
    ');
    			//*/
    		}
    	}
    	return 0;
    }
    

    暴力

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    long long read() {
    	long long re = 0;
    	char c = getchar();
    	
    	while(c < '0' || c > '9')c = getchar();
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0',
    		c = getchar();
    	return re;
    }
    
    int n , m;
    ll a[100010];
    int main() {
    	n = read();
    	for(int i = 1 ; i <= n ; i++)
    		a[i] = read();
    	
    	m = read();
    	for(int i = 1 ; i <= m ; i++) {
    		int op = read() , l = read() , r = read();
    		if(l > r) swap(l , r);
    		if(op == 0)
    			for(int j = l ; j <= r ; j++)
    				a[j] = (int)sqrt(a[j]);
    		else {
    			ll ans = 0;
    			for(int j = l ; j <= r ; j++) {
    				ans += a[j];
    			}
    			printf("%lld
    " , ans);
    		}
    	}
    		
    	return 0;
    }
    

    数据生成

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    ll random(ll r , ll l = 1) {
    	return l == r ? l : abs((ll)rand() * rand() % (r - l) + l);
    }
    int main() {
    	srand((unsigned)(time(0)));
    	
    	int n = random(100000 , 100000);
    	printf("%d
    " , n);
    	for(int i = 1 ; i <= n ; i++)
    		printf("%lld " , random(1000000000000ll));
    	putchar('
    ');
    	
    	int m = random(100000 , 100000);
    	printf("%d
    " , m);
    	for(int i = 1 ; i <= m ; i++) {
    		printf("%d %d %d
    " , random(100) % 2 ^ 1 , random(n) , random(n));
    	}
    	return 0;
    }
    

    对拍控制

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
    	int cnt = 0;
    	while(true) {
    		++cnt;
    		printf("
    #%d
    " , cnt);
    		system("random.exe > input.txt");
    		puts("random");
    		
    		int t = clock();
    		if(system("tested < input.txt > output2.txt") != 0) {
    			cout << "RE";
    			break;
    		}
    		puts("tested");
    		printf(">time : %d
    " , clock() - t);
    		continue;//删掉这里开启对拍,否则为单纯性能测试
    		
    		system("std.exe < input.txt > output1.txt");
    		puts("std");
    		
    		if(system("fc output1.txt output2.txt")) {
    			cout << "WA";
    			break;
    		}
    	}
    	system("start input.txt"); 
    	return 0;
    }
    
  • 相关阅读:
    反射API(二)
    反射API(一)
    session一二事
    自定义session的存储机制
    JavaScript 入门笔记
    PHP引用赋值
    九九乘法口诀表
    PHP流程控制笔记
    PHP函数总结 (七)
    Linux程序编辑器习题汇总
  • 原文地址:https://www.cnblogs.com/dream1024/p/14044350.html
Copyright © 2011-2022 走看看