第二场纳新赛

C.天天乐乐

每个任务花\(c_i\)完成,在时间\(t\)完成,得到价值\(a_i - t * b_i\)
按bi从大到小排序,然后看哪个选不选, f[i][j]表示前i个,j的时间最多的价值

F.字符串

找所有的子串s(l,r),使s(1, r - l + 1) = s(l:r)

J.幂次

赛时的题,\(l,r<=1e18\)\(f(l, r)\)也就是calc(r)的过程中到l就停止
The 23rd Sichuan University Programming Contest D.MISagain
calc(y) = sum以y为右端点的区间的|S|
calc(y) = calc(2^(k + 1) - y - 1) + 段间 + 本段内
+ 段间长度 * 后缀最大值(不能取段间的数,都和后面的|S|一样) + 段内等差

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define ft first
#define se second
#define yes cout << "Yes\n"
#define no cout << "No\n"
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
typedef long double ld;
typedef long long ll;
typedef __int128 LL;
typedef pair<int, int> pii;

int n;
const int V = 500005;
int lst[V];
ll f[V];


ll calc(int y, int sum){
	if(y <= 0) return 0;
	int len = y - lst[y] + 1;
	ll ret = 1ll * (sum + 1 + sum + len) * len / 2;
	sum += (y - lst[y] + 1);
	ret += 1ll * sum * max(0, lst[y] - (lst[y] * 2 - y));
	ret += calc(lst[y] * 2 - y - 1, sum);

	return ret;
}
void init(){
	for(int i = 1; i < V; i *= 2) lst[i] = i;
	for(int i = 1; i < V; i ++) if(!lst[i]) lst[i] = lst[i - 1]; 

	for(int i = 1; i < V; i ++) f[i] = calc(i, 0);
	for(int i = 1; i < V; i ++) f[i] += f[i - 1];
}


void solve(){
	cin >> n;
	cout << f[n] << '\n';
}

signed main()
{
    std::ios::sync_with_stdio(false);
    init();
    int T = 1;
    cin >> T;
    while(T -- ){
        solve();
    }
}
posted @ 2026-03-23 00:26  arin876  阅读(1)  评论(0)    收藏  举报