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 }

 

转载于:https://www.cnblogs.com/mzl120918/p/5776190.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值