bzoj 2058+2059+2060 Usaco2010 Nov
三道金组比较容易的题目。。
2058
首先交换次数就是逆序对数,因为只能交换相邻的两数
先对原序列找逆序对数
用树状数组nlogn求出
然后O(n)依次求出其循环序列的逆序对数
比如 3 5 4 2 1
循环之后相对应的位置变成
2 4 3 1 5
表示第一个数到位置2,第二个数到位置4,第三个数到位置1 etc.
那么依次减一的那些数的逆序对数是不变的。只有1变成5的那个增加或减少了逆序对数
由于5是序列里最大的数,设其所在位置为i,因此增加了n-i对,减少了i-1对
这样总复杂度就是nlogn的
记得开Long long
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #define LL long long 5 using namespace std; 6 struct node{ 7 int v,id; 8 }a[100010]; 9 LL tot,ans,p[100010]; 10 int n; 11 12 bool cmp(node a, node b){ 13 return a.v<b.v; 14 } 15 16 void add(int x){ 17 while (x<=n){ 18 p[x]++; 19 x+=x&-x; 20 } 21 } 22 23 LL sum(int x){ 24 LL ret=0; 25 while (x){ 26 ret+=p[x]; 27 x-=x&-x; 28 }return ret; 29 } 30 31 int main(){ 32 scanf("%d", &n); 33 for (int i=1; i<=n; i++) scanf("%d", &a[i].v), a[i].id=i,p[i]=0; 34 tot=0; 35 for (int i=1; i<=n; i++){ 36 add(a[i].v); 37 tot+=(LL)i-sum(a[i].v); 38 } 39 sort(a+1,a+1+n,cmp); 40 ans=tot; 41 for (int i=1; i<=n; i++){ 42 int del=n-a[i].id-(a[i].id-1); 43 tot+=(LL)del; 44 ans=min(ans,tot); 45 } 46 printf("%lld\n", ans); 47 return 0; 48 }
2059
单调队列DP,降复杂度为O(NK)
分n阶段进行单调队列的优化dp
设dis=a[i].x-a[i-1].x
f[i][k]=cost[i]*k+min{f[i-1][j]-cost[i]*j+dis*j*j};
显然f[i][k]只与f[i-1][k]有关所以省略一维,并且先插入队列(此时为f[i-1][k]的值),然后再更新为f[i][k]
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #define LL long long 5 using namespace std; 6 const int maxn = 800010; 7 struct node{ 8 int x,f; 9 LL c; 10 }a[maxn]; 11 struct que{ 12 int v; 13 LL val; 14 }q[maxn*2]; 15 int K,end,n; 16 LL f[maxn]; 17 18 bool cmp(node a, node b){ 19 return a.x<b.x; 20 } 21 22 int main(){ 23 scanf("%d%d%d", &K, &end, &n); 24 for (int i=1; i<=n; i++) scanf("%d%d%lld", &a[i].x, &a[i].f, &a[i].c); 25 sort(a+1,a+1+n,cmp); 26 memset(f,0x3f3f3f3f,sizeof(f)); 27 f[0]=0; 28 for (int i=1; i<=n; i++){ 29 int head=0, tail=0; 30 LL dis=a[i].x-a[i-1].x; 31 q[tail].v=0,q[tail].val=0,tail++; 32 for (int j=1; j<=K; j++){ 33 LL now=f[j]-(LL)j*a[i].c+dis*(LL)j*(LL)j; 34 while (head<tail && q[tail-1].val>=now) tail--; 35 q[tail].v=j, q[tail].val=now, tail++; 36 while (head<tail && q[head].v+a[i].f<j) head++; 37 f[j]=q[head].val+(LL)j*a[i].c; 38 } 39 } 40 printf("%lld\n", f[K]+(LL)K*(LL)K*(LL)(end-a[n].x)); 41 return 0; 42 }
2060
树形dp的入门水题。。
f[u]表示选u的最大值
g[u]表示不选u的最大值
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 100010; 6 struct node{ 7 int to,next; 8 }e[maxn]; 9 int g[maxn],f[maxn],n,head[maxn],tot,u,v; 10 11 void insert(int u, int v){ 12 e[++tot].to=v; e[tot].next=head[u]; head[u]=tot; 13 } 14 15 void dfs(int x, int fa){ 16 g[x]=0; f[x]=1; 17 for (int i=head[x]; i!=-1; i=e[i].next){ 18 int v=e[i].to; 19 if (v==fa) continue; 20 dfs(v,x); 21 g[x]+=max(g[v],f[v]); 22 f[x]+=g[v]; 23 } 24 } 25 26 int main(){ 27 scanf("%d", &n); 28 tot=1; memset(head,-1,sizeof(head)); 29 for (int i=1; i<n; i++){ 30 scanf("%d%d", &u, &v); 31 insert(u,v); insert(v,u); 32 } 33 dfs(1,0); 34 printf("%d\n", max(g[1],f[1])); 35 return 0; 36 }