广工校赛复盘CD题

C题:3s

鸽子数字由以下过程定义:从任何正整数开始,将数字替换为其数字的十进制数字的平方和,并重复该过程,直到该数字等于1。如果不能,则这个数字不是鸽子数。
输入:
第一行Q,代表询问的个数(Q<=100000)
接下来Q行,每行给出一个数k,问第k个鸽子数。(k<150000)

输入示例:
2
1
2

输出示例:
1
7

题解:如果一个数不是鸽子数,那么循环节长度为 8,显然打表至k=150000即可,关键是要判到vis数组开多大防tle

#include <bits/stdc++.h>
using namespace std;
int f[1000000],vis[81*15],t;
bool check(int x){
    if(x==1)return true;//特判1就跳出
    memset(vis,0,sizeof vis);//清空访问表
    while(1){
        t=0;
        while(x){//把x的每个位求平方和
            t+=(x%10)*(x%10);
            x/=10;
        }
        if(vis[t]==0)vis[t]=1;//未VIS过就打上标记
        else//如果VIS过了就表示循环了
            if(t==1)return true;//能够到1就是鸽子数
            else return false;//不能的话就不是
        x=t;//然后x记为t
    }
}
void init(){
    int cnt=1;
    for(int i=1;i<1000000;i++)
        if(check(i))//打表,check对了就压入
            f[cnt++]=i;
    return;
}
int main(){
    init();//打个表求第N个鸽子数
    int q;scanf("%d",&q);
    while(q--){
        int n;scanf("%d",&n);
        printf("%d\n",f[n]);
    }
    return 0;
}

D题:免费送气球

已知一开始有一个空序列,接下来有Q次操作,每次操作给出type、first和second三个值。
当type为1时,意味着该操作属于第一种操作:往序列尾部添加first个second数。
当type为2时,意味着该操作属于第二种操作:查询序列中第first小至第second小的数值之和(一共有(second - first + 1)个数被累加),并将结果对1000000007取模后输出。

## Input
单组数据
第一行一个Q(1 <= Q <= 1e5),代表Q次操作。
接下来有Q行,每行包含三个整数type、first和second;其中1 <= type <= 2。当type等于1时,0 <= first,second < 1e9。当type等于2时,1 <= first <= second,且first和second均不大于目前已添加进序列的数的数量。

## Output
对于每次操作二,将结果对1000000007取模后输出。

## Sample Input
6  
1 5 1  
1 6 3  
2 2 5  
2 4 8  
1 2 2  
2 4 8

## Sample Output
4  
11  
9

首先将所有将要添加的数离散化,然后建立两颗线段树,分别维护区间内数的数量和区间和。对于操 作一,根据离散化后的值在线段树对应位置添加 k 个 val,并维护线段树每一个节点所代表区间的和。 对于操作二,首先将问题转化成两个前 k 小之和的查询,具体做法:传入参数 k 搜索线段树,先递归 检查左子区间的数的数量,如果小于当前 k,再传入当前 k-'左子区间的数的数量'作为更新后的参数 k 递归搜索右子区间;递归搜索时,应将满足数量条件(当前区间的数的数量小于等于 k)等于的区间和 累加并返回作为答案。 

当然只建一棵也是可以的,结点开结构体同时存和值与数量即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-10;
const int N = 1e5 + 5;
int Q, n, _n, type[N];
P p[N];
ll w[N], num[N << 2], sum[N << 2];
map<ll, ll> Map;
void init() {
	memset(w, 0, sizeof w);
	n = 0;
	for (auto &t : Map) {
		w[n] = t.first;
		t.second = n++;
	}
	_n = 1;
	while (_n < n) _n <<= 1;
	memset(num, 0, sizeof num);
	memset(sum, 0, sizeof sum);
}
void add(int pos, ll k, ll val, int l = 0, int r = _n, int t = 0) {
	num[t] += k;
	sum[t] = (sum[t] + val) % mod;
	if (r - l == 1) return;
	int mid = l + r >> 1;
	if (pos < mid) add(pos, k, val, l, mid, t << 1 | 1);
	else add(pos, k, val, mid, r, t + 1 << 1);
}
ll query(ll &k, int t = 0) {
	if (k == 0) return 0;
	if (k >= num[t]) {
		k -= num[t];
		return sum[t];
	}
	if (t + 2 > _n) {//判断是否为叶子节点
		ll ret = k*w[t - _n + 1] % mod;
		k = 0;
		return ret;
	}
	return (query(k, t << 1 | 1) + query(k, t + 1 << 1)) % mod;
}
int main(){
	scanf("%d", &Q);
	Map.clear();
	for (int i = 0; i < Q; ++i) {
		scanf("%d %lld %lld", type + i, &p[i].first, &p[i].second);
		if (type[i] == 1) Map[p[i].second];
	}
	init();
	for (int i = 0; i < Q; ++i) {
		if (type[i] == 1) {
			add(Map[p[i].second], p[i].first, p[i].first*p[i].second%mod);
		}
		else {
			ll l = p[i].first - 1, r = p[i].second;
			printf("%lld\n", (query(r) - query(l) + mod) % mod);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/cj1064789374/article/details/88653017