T1
思路
直接预处理出两个数组,然后用树状数组维护一下就行了。注意树状数组开两倍空间
代码
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<map>
#include<ctime>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
map<int,int>ma;
const int N = 200000 + 100;
int mod;
ll read() {
ll x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
int f[N],g[N];
int ls;
int tmp[N * 2];
ll qm(ll x,int y) {
if(x == 0) return 0;
ll ans = 1;
x %= mod;
for(;y;y >>= 1,x = x * x % mod)
if(y & 1) ans = ans * x % mod;
return ans;
}
int now;
int n;
void lisan() {
sort(tmp + 1,tmp + ls + 1);
tmp[0] = -1;
for(int i = 1;i <= ls;++i) {
if(tmp[i] != tmp[i-1])
ma[tmp[i]] = ++now;
}
for(int i =1 ;i <= n;++i) {
f[i] = ma[f[i]];
g[i] = ma[g[i]];
}
}
int tree[N * 10];
void add(int pos,int c) {
while(pos <= now) {
tree[pos] += c;
pos += pos & -pos;
}
}
int query(int pos) {
int ans = 0;
while(pos >= 1) {
ans += tree[pos];
pos -= pos & -pos;
}
return ans;
}
int main() {
freopen("calc.in","r",stdin);
freopen("calc.out","w",stdout);
n = read();
mod = read();
for(int i = 1;i <= n;++i) {
int k = read();
f[i] = qm(i,k);
g[i] = qm(k,i);
tmp[++ls] = f[i];
tmp[++ls] = g[i];
}
lisan();
ll ans = 0;
for(int i = n;i >= 1;--i) {
ans += query(f[i] - 1);
add(g[i],1);
}
cout<<ans;
return 0;
}
/*
5 10000
3 1 5 4 2
*/
T2
思路
显然需要二分一下最小的有效值。然后当当前的防御力不够的时候,贪心的将当前点之后的第R个点的攻击力加上相差的值。容易证明这种贪心是对的。
这里的r是longlong类型的,结果二分的时候的mid是int类型的。然后死循环。。。。。
代码
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 500000 + 100;
ll read() {
ll x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
int n;
int R;
ll K;
ll a[N];
ll sum[N],fy[N],tmp[N];
void pre() {
for(int i = 1;i <= n;++i)
sum[i] = sum[i-1] + a[i];
for(int i = 1;i <= n;++i)
fy[i] = sum[min(n,i + R)] - sum[max(1,i - R) -1];
}
int check(ll x) {
memset(tmp,0,sizeof(tmp));
ll re = 0,now = 0;
for(int i = 1;i <= n;++i) {
if(i - R >= 1) now -= tmp[i-R-1];
ll z = x - fy[i] - now;
if(z <= 0) continue;
tmp[min(n,i + R)] += z;
re += z;
now += z;
if(re > K) return 0;
}
return 1;
}
int main() {
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
n = read(), R = read(),K = read();
for(int i = 1;i <= n;++i) a[i] = read();
pre();
ll r = 0;
for(int i = 1;i <= n;++i) r = max(r,fy[i] + K);
ll l = 0;
ll ans = 0;
while(l <= r) {
ll mid = (l + r) >> 1;//!!!!
if(check(mid)) ans = mid,l = mid + 1;
else r = mid - 1;
}
cout<<ans;
return 0;
}
/*
5 0 6
5 4 3 4 9
*/
T3
思路
考虑用并查集。发现w比k小,所以先预处理出来,然后再查询,将边排个序,给并查集赋个权值表示这个联通块的大小,然后在合并的时候统计最大联通块就行了。
用tmp[0]记录tmp数组的个数,结果二分的时候查询到了0这个位置。。。。。。。。。。
代码
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 100000 + 100;
queue<int>q;
ll read() {
ll x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
struct node {
int u,v,nxt,w;
}e[N << 1];
int head[N],ejs;
int n,m,Q;
void add(int u,int v,int w) {
e[++ejs].v = v; e[ejs].nxt = head[u];head[u] = ejs;e[ejs].w = w;
}
namespace BF1 {
int ans[N],vis[N],tmp[N];
int bfs(int U,int x) {
while(!q.empty()) q.pop();
q.push(U);
vis[U] = 1;
int re = 0;
while(!q.empty()) {
int u = q.front();q.pop();
for(int i = head[u];i;i = e[i].nxt) {
if(e[i].w > x) continue;
int v = e[i].v;
re += e[i].w;
if(!vis[v]) q.push(v),vis[v] = 1;
}
}
return re>>1;
}
int solve(int x) {
memset(vis,0,sizeof(vis));
int re = 0;
for(int i = 1;i <= n;++i)
if(!vis[i])
re = max(re,bfs(i,x));
return re;
}
int find(int x) {
int l = 0,r = tmp[0];
int re = 0;
while(l <= r) {
int mid = (l + r) >> 1;
if(tmp[mid] <= x) re = mid,l = mid + 1;
else r = mid - 1;
}
return re;
}
void Main() {
int NAME = 0;
for(int i = 1;i <= m;++i) {
int u = read(),v = read(),w = read();
add(u,v,w);
add(v,u,w);
tmp[++tmp[0]] = w;
NAME = max(NAME,w);
}
sort(tmp + 1,tmp + tmp[0] + 1);
for(int i = 1; i <= tmp[0]; ++i) {
ans[i] = solve(tmp[i]);
}
for(int i = 1;i <= Q;++i)
printf("%d\n",ans[find(read())]);
}
}
namespace BF2 {
int fa[N],siz[N];
bool cmp(node x,node y) {
return x.w < y.w;
}
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void uni(int x,int y) {
x = find(x),y = find(y);
if(rand() & 1) swap(x,y);
fa[x] = y;
siz[y] += siz[x];
siz[x] = 0;
}
int tmp[N],ans[N];
int query(int x) {
int l = 1,r = tmp[0];
int re = 0;
while(l <= r) {
int mid = (l + r) >> 1;
if(tmp[mid] <= x) re = mid,l = mid + 1;
else r = mid - 1;
}
return re;
}
void Main() {
for(int i = 1;i <= n;++i) fa[i] = i;
for(int i = 1;i <= m;++i) e[i].u = read(),e[i].v = read(),e[i].w = read();
sort(e + 1,e + m + 1,cmp);
int now = 1;
e[0].w = -1;
for(int i = 1;i <= m;++i) {
if(e[i].w != e[i-1].w) tmp[++tmp[0]] = e[i].w;
}
for(int i = 1;i <= tmp[0];++i) {
ans[i] = ans[i-1];
int x = tmp[i];
while(e[now].w <= x && now <= m) {
int k1 = find(e[now].u),k2 = find(e[now].v);
if(k1 == k2) {
ans[i] = max(ans[i],siz[k2] + e[now].w);
siz[k2] += e[now].w;
}
else {
siz[k1] += e[now].w;
ans[i] = max(ans[i],siz[k1] + siz[k2]);
uni(k1,k2);
}
++now;
}
}
while(Q--) {
int x = read();
printf("%d\n",ans[query(x)]);
}
}
}
int main() {
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
srand(time(0));
n = read(), m = read(),Q = read();
BF2::Main();
return 0;
}
/*
5 5 3
1 2 5
2 3 6
3 4 4
3 5 2
4 5 3
7
5
3
6 6 10
1 2 3
1 3 4
2 3 4
2 5 5
5 3 3
总结
期望得分:100 + 100 + 100 = 300
实际得分:100 + 20 + 40 = 160
细节决定成败,写错三个字,送走140分。。
一言
我这份不断涌现的思念之情,不想让你知道,但却又不能停止。