题解
今天的题…错误还比较多…但..错的是题面……所以今天的高分真的是水出来的……我真的是个垃圾OIer
第一题——序列(sequence)
【题目描述】
- 给出一个长度为3N的正整数序列。要求一个长度为2N的子序列,使得该子序列的前面N个元素的和减去后面N个元素的和最大。求这个最大值(
题干就这么长)
- 刚拿到手之后没有什么思路,但是想了想之后发现:
- 前面的n个元素是一定归前面所选择的,同理后面n个元素也是归后面选择的。那就只要枚举中间端点来进行前后的分块,用大根堆和小根堆维护前面的最大值和后面的最小值就可以。然后扫一遍求出答案。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define LL long long
using namespace std;
void fff(){
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
}
const int MAXN=300100;
int n;
LL a[MAXN];
priority_queue<LL,vector<LL>,less<LL> > q2;
priority_queue<LL,vector<LL>,greater<LL> > q1;
LL f1[MAXN],f2[MAXN];
LL s1,s2,maxx;
int main(){
fff();
scanf("%d",&n);
s1=0,s2=0;
maxx=0;
for (int i=1;i<=3*n;i++){
scanf("%lld",&a[i]);
}
for (int i=1;i<=n;i++){
q1.push(a[i]);
s1+=a[i];
q2.push(a[3*n-i+1]);
s2+=a[3*n-i+1];
}
f1[n]=s1;
for (int i=n+1;i<=2*n;i++){
f1[i]=f1[i-1];
if(a[i]>q1.top()){
f1[i]-=q1.top();
f1[i]+=a[i];
q1.pop();
q1.push(a[i]);
}
}
f2[2*n+1]=s2;
for (int i=2*n;i>n;i--){
f2[i]=f2[i+1];
if(a[i]<q2.top()){
f2[i]-=q2.top();
f2[i]+=a[i];
q2.pop();
q2.push(a[i]);
}
maxx=max(maxx,f1[i]-f2[i+1]);
}
printf("%lld",maxx);
return 0;
}
第二题——最大公约数(gcd)
【题目描述】
- 给出2个正整数数组 a[0..n−1] a [ 0.. n − 1 ] , b[0..m−1] b [ 0.. m − 1 ] ,定义nm二维数组 c[i][j]=gcd(a[i],b[j]) c [ i ] [ j ] = g c d ( a [ i ] , b [ j ] ) ,给出q个形如 r1,c1,r2,c2 r 1 , c 1 , r 2 , c 2 的询问,询问 c[r1..r2][c1..c2] c [ r 1.. r 2 ] [ c 1.. c 2 ] 这个子矩形里有多少个不同的数。
- 讲道理这道题我只会打爆力。骗了40分。
- 正解还是用倍数法来做。(lzw4896s的惯用打法)
- 用 f[i] f [ i ] 表示从 a[r1..r2] a [ r 1 . . r 2 ] b[r1..r2] b [ r 1 . . r 2 ] 取出一对, gcd g c d 刚好为 i i 的倍数的方案。
- 用表示从 a[r1..r2] a [ r 1 . . r 2 ] b[r1..r2] b [ r 1 . . r 2 ] 取出一对, gcd g c d 刚好为 i i 的方案。
- 那么可以递推求出
- f[i] f [ i ] 可以在先前进行预处理:( a[i] a [ i ] 当中是 i i 的倍数有多少个)*(当中是 i i 的倍数有多少个)。复杂度就是。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 100010
#define LL long long
using namespace std;
void fff(){
freopen("gcd.in","r",stdin);
freopen("gcd.out","w",stdout);
}
const int MAXN=100010;
int n,m,q,cnt;
int a[MAXN],b[MAXN];
bool visited[MAXN*12];
int cnt1[MAXN],cnt2[MAXN],d1[MAXN],d2[MAXN];
LL f[MAXN],g[MAXN];
int gcd(int a,int b){
return (b==0)?a:gcd(b,a%b);
}
int solve(int r1,int r2,int c1,int c2){
memset(cnt1,0,sizeof(cnt1));
memset(cnt2,0,sizeof(cnt2));
memset(d1,0,sizeof(d1));
memset(d2,0,sizeof(d2));
for (int i=r1;i<=r2;i++) cnt1[a[i]]++;
for (int i=c1;i<=c2;i++) cnt2[b[i]]++;
for (int i=1;i<N;i++){
for (int j=i;j<N;j+=i)
d1[i]+=cnt1[j];
}
for (int i=1;i<N;i++){
for (int j=i;j<N;j+=i)
d2[i]+=cnt2[j];
}
int res=0;
for (int i=1;i<N;i++) g[i]=1ll*d1[i]*d2[i];
for (int i=N-1;i>=1;i--){
f[i]=g[i];
for (int j=2*i;j<N;j+=i) f[i]-=f[j];
if(f[i]) res++;
}
return res;
}
int main(){
fff();
scanf("%d%d%d",&n,&m,&q);
for (int i=0;i<n;i++){
scanf("%d",&a[i]);
}
for (int i=0;i<m;i++){
scanf("%d",&b[i]);
}
for (int i=1;i<=q;i++){
int r1,r2,c2,c1;
scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
memset(visited,false,sizeof(visited));
cnt=0;
printf("%d\n",solve(r1,r2,c1,c2));
}
return 0;
}
第三题——染色(color)
【题目描述】
- N个点M条边的无向无环图,无重边和自环。一开始所有的点都是颜色0
。接下来有Q次操作,每次操作形如x d c表示将与点x距离不超过d的点全部染成颜色c(同一个点之后染的颜色会覆盖之前的)。问Q次操作结束后每个点的颜色。
- 讲道理..原来题干是有向无环图但std打的是无向图….然后就爆零了。改成有向图再测,只有四十分。(毕竟是暴力算法)
- 在之前又想到过正解。由于会被覆盖,则只需要采取一种离线算法。从后往前进行覆盖。保证每一个点只会被读到一次。但会发现。当当前这个节点已经被覆盖了之后,他身后的节点在下一次染色的时候无法被读取。就很尴尬了……考场上没有办法解决这个问题。而标程利用d很好的解决了这个问题。
- 把染色数组改变成一个二维数组。 color[N][d] c o l o r [ N ] [ d ] 表示在第N个点第d步被染过色。这样子可以有效地预防后效,同时也能避免对下一步的子节点有影响。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <vector>
using namespace std;
void fff(){
freopen("color.in","r",stdin);
freopen("color.out","w",stdout);
}
const int MAXN=101000;
int n,m,q;
struct node{
int x,d,c;
}Q[MAXN];
queue <node>quq;
vector <int> G[MAXN];
bool visited[MAXN];
int color[MAXN][11];
void solve(int x,int d,int c){
if(color[x][d]) return;
color[x][d]=c;
if(d==0) return;
int siz=G[x].size();
for (int i=0;i<siz;i++){
solve(G[x][i],d-1,c);
}
solve(x,d-1,c);
}
int main(){
fff();
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
scanf("%d",&q);
for (int i=1;i<=q;i++){
int x,d,c;
scanf("%d%d%d",&Q[i].x,&Q[i].d,&Q[i].c);
}
for (int i=q;i>=1;i--){
solve(Q[i].x,Q[i].d,Q[i].c);
}
for(int i=1;i<=n;i++){
printf("%d\n",color[i][0]);
}
return 0;
}