POI

[POI2007]MEG-Megalopolis

题意:https://www.luogu.org/problemnew/show/P3459

分析:发现查询的起点总是1。把边下放到点,树剖裸上。注意1号点是不要的。

代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <algorithm>
  4 using namespace std;
  5 #define N 250050
  6 #define lson pos<<1
  7 #define rson pos<<1|1
  8 int head[N],to[N<<1],nxt[N<<1],cnt,tot;
  9 int n,m,dep[N],fa[N],son[N],siz[N],top[N],idx[N];
 10 int t[N<<2];
 11 char ch[10];
 12 void read(int &x)
 13 {
 14     int f=1;x=0;char s=getchar();
 15     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
 16     while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
 17     x*=f;   
 18 }
 19 inline void add(int u,int v)
 20 {
 21     to[++cnt]=v;
 22     nxt[cnt]=head[u];
 23     head[u]=cnt;    
 24 }
 25 void dfs1(int x,int y)
 26 {
 27     dep[x]=dep[y]+1;
 28     fa[x]=y;
 29     siz[x]=1;
 30     for(int i=head[x];i;i=nxt[i])
 31     {
 32         if(to[i]==y)continue;
 33         dfs1(to[i],x);
 34         siz[x]+=siz[to[i]];
 35         if(siz[to[i]]>siz[son[x]])
 36         {
 37             son[x]=to[i];   
 38         }
 39     }
 40 }
 41 void dfs2(int x,int t)
 42 {
 43     top[x]=t;idx[x]=++tot;
 44     if(son[x])dfs2(son[x],t);
 45     for(int i=head[x];i;i=nxt[i])
 46     {
 47         if(to[i]==fa[x]||to[i]==son[x])continue;
 48         dfs2(to[i],to[i]);  
 49     }
 50 }
 51 void bt(int l,int r,int pos)
 52 {
 53     if(l==r)
 54     {
 55         t[pos]=1;return ;
 56     }
 57     int mid=l+r>>1;
 58     bt(l,mid,lson);
 59     bt(mid+1,r,rson);
 60     t[pos]=t[lson]+t[rson];
 61 }
 62 void up(int l,int r,int x,int y,int pos)
 63 {
 64     if(t[pos]==0)return ;
 65     if(x<=l&&r<=y)
 66     {
 67         t[pos]=0;return ;
 68     }
 69     int mid=l+r>>1;
 70     if(x<=mid)up(l,mid,x,y,lson);
 71     if(y>mid)up(mid+1,r,x,y,rson);
 72     t[pos]=t[lson]+t[rson];
 73 }
 74 int query(int l,int r,int x,int y,int pos)
 75 {
 76     if(x<=l&&r<=y)return t[pos];
 77     int re=0,mid=l+r>>1;
 78     if(x<=mid)re+=query(l,mid,x,y,lson);
 79     if(y>mid)re+=query(mid+1,r,x,y,rson);
 80     return re;
 81 }
 82 int main()
 83 {
 84     scanf("%d",&n);
 85     bt(1,n,1);
 86     int x,y;
 87     for(int i=1;i<n;i++)
 88     {
 89         scanf("%d%d",&x,&y);
 90         add(x,y);
 91         add(y,x);
 92     }
 93     dfs1(1,0);
 94     dfs2(1,1);
 95     scanf("%d",&m);
 96     for(int i=1;i<n+m;i++)
 97     {
 98         scanf("%s",ch);
 99         if(ch[0]=='W')
100         {
101             scanf("%d",&x);
102             y=1;
103             int ans=0;
104             while(top[x]!=top[y])
105             {
106                 if(dep[top[x]]>dep[top[y]])swap(x,y);
107                 ans+=query(1,n,idx[top[y]],idx[y],1);
108                 y=fa[top[y]];   
109             }
110             if(dep[x]<dep[y])swap(x,y);
111             ans+=query(1,n,idx[y],idx[x],1);
112             printf("%d\n",ans-1);
113         }
114         else
115         {
116             scanf("%d%d",&x,&y);
117             if(x>y)swap(x,y);
118             if(x==1)
119             {
120                 up(1,n,idx[y],idx[y],1);
121             }
122             else if(fa[x]==y)
123             {
124                 up(1,n,idx[x],idx[x],1);    
125             }
126             else
127             {
128                 up(1,n,idx[y],idx[y],1);
129             }
130         }
131     }
132 }
View Code

 

[POI2007]ZAP-Queries

这里:http://www.cnblogs.com/suika/p/8416136.html

 

[POI2008]PLA-Postering

题意:https://www.luogu.org/problemnew/show/P3467

分析:维护一个单调增的栈,如果当前高度大于栈顶,ans+1;否则弹栈直到栈顶小于等于当前高度。

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 int st[250050],top,n,ans;
 6 int main()
 7 {
 8     scanf("%d",&n);
 9     int x,y;
10     for(int i=1;i<=n;i++)
11     {
12         scanf("%d%d",&y,&x);
13         if(top==0)
14         {
15             ans++;
16             st[top++]=x;continue;    
17         }
18         if(x<=st[top-1])
19         {
20             while(top&&x<st[top-1])top--;
21             if(!top||x>st[top-1])ans++;
22             st[top++]=x;
23         }
24         else
25         {
26             ans++;
27             st[top++]=x;    
28         }
29     }
30     printf("%d",ans);
31 }
View Code

 

[POI2005]SKA-Piggy Banks

题意:https://www.luogu.org/problemnew/show/P3420

分析:每个罐子向里面含有的钥匙连边,显然图中不会有复杂的环套环这种,考虑每个联通快,如果是环则对答案贡献为1,否则对答案贡献为入度为0的点的个数。

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 #define N 1000010
 6 int n,fa[N],ans,c[N],f[N];
 7 void read(int &x)
 8 {
 9     int f=1;x=0;char s=getchar();
10     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
11     while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
12     x*=f;    
13 }
14 int find(int x)
15 {
16     return fa[x]^x?fa[x]=find(fa[x]):x;
17 }
18 int main()
19 {
20     read(n);
21     register int i;
22     int x;
23     for(i=1;i<=n;++i)fa[i]=i;
24     for(i=1;i<=n;++i)
25     {
26         read(x);
27         int di=find(i),dx=find(x);
28         c[i]++;
29         fa[di]=dx;
30     }
31     for(i=1;i<=n;++i)
32     {
33         if(fa[i]==i)ans++;    
34     }
35     for(i=1;i<=n;++i)
36     {
37         if(!c[i])
38         {
39             int di=find(i);
40             if(!f[di])f[di]=1;
41             else ans++;
42         }
43     }
44     printf("%d",ans);
45 }
View Code

 

[POI2008]STA-Station

题意:给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大

分析:树形DP,换根时减去儿子的子树大小加上n-儿子的子树大小。

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 #define N 1000010
 6 #define LL long long
 7 int head[N],to[N<<1],nxt[N<<1],cnt,n;
 8 int dep[N],fa[N],siz[N],ans;
 9 LL sum[N],mx;
10 void read(int &x)
11 {
12     int f=1;x=0;char s=getchar();
13     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
14     while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}x*=f;    
15 }
16 inline void add(int u,int v)
17 {
18     to[++cnt]=v;
19     nxt[cnt]=head[u];
20     head[u]=cnt;    
21 }
22 void dfs(int x,int y)
23 {
24     siz[x]=1;
25     dep[x]=dep[y]+1;
26     sum[1]+=dep[x];
27     fa[x]=y;
28     register int i;
29     for(i=head[x];i;i=nxt[i])
30     {
31         if(to[i]==y)continue;
32         dfs(to[i],x);
33         siz[x]+=siz[to[i]];
34     }
35 }
36 void niu(int x)
37 {
38     register int i;
39     for(i=head[x];i;i=nxt[i])
40     {
41         if(to[i]==fa[x])continue;
42         sum[to[i]]=sum[x]-(siz[to[i]]-1)+(n-siz[to[i]]-1);
43         if(sum[to[i]]>mx)
44         {
45             ans=to[i];mx=sum[to[i]];        
46         }
47         else if(sum[to[i]]==mx&&to[i]<ans)ans=to[i];
48         niu(to[i]);
49     }
50 }
51 int main()
52 {
53     read(n);
54     int x,y;
55     register int i;
56     for(i=1;i<n;++i)
57     {
58         read(x);read(y);
59         add(x,y);add(y,x);    
60     }
61     dfs(1,0);
62     ans=1;
63     mx=sum[1];
64     niu(1);
65     printf("%d",ans);
66 }
View Code

 

[POI2008]BLO

题意:Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 所有towns连通。

分析:如果这个点不是割点,答案为2*n-2,否则需要加上以割点子节点为根的节点个数和剩余节点互相的乘积之和。

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 #define N 100050
 6 #define M 1000050
 7 #define LL long long
 8 int head[N],to[M],nxt[M],siz[N],n,m,cnt;
 9 LL ans[N];
10 int dfn[N],low[N],tot,cur[N];
11 inline void add(int u,int v){
12     to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
13     to[++cnt]=u;nxt[cnt]=head[v];head[v]=cnt;
14 }
15 void read(int &x){
16     int f=1;x=0;char s=getchar();
17     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
18     while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}x*=f;
19 }
20 void tarjan(int x){
21     dfn[x]=low[x]=++tot;siz[x]=1;
22     int sum=0,flg=0;
23     for(int i=head[x];i;i=nxt[i]){
24         if(!dfn[to[i]]){
25             tarjan(to[i]);
26             siz[x]+=siz[to[i]];
27             low[x]=min(low[x],low[to[i]]);
28             if(low[to[i]]>=dfn[x]){
29                 flg++;
30                 ans[x]+=1ll*siz[to[i]]*(n-siz[to[i]]);
31                 sum+=siz[to[i]];
32                 if(x!=1||flg>1){
33                     cur[x]=1;
34                 }
35             }
36         }
37         else low[x]=min(low[x],dfn[to[i]]);
38     }
39     if(cur[x]){
40         ans[x]+=1ll*(n-sum-1)*(sum+1)+(n-1);
41     }else ans[x]=2*(n-1);
42 }
43 int main(){
44     read(n),read(m);
45     int x,y;
46     for(int i=1;i<=m;i++){
47         read(x),read(y);
48         add(x,y);
49     }
50     tarjan(1);
51     for(int i=1;i<=n;i++){
52         printf("%lld\n",ans[i]);
53     }
54 }
View Code

 

[POI2008]CLO

题意:Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 你要把其中一些road变成单向边使得:每个town都有且只有一个入度。

分析:对于每个连通块,能够满足条件当且仅当连通块中边数大于等于点数,即存在环,用并查集维护一下就行。

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 #define N 100020
 6 int n,fa[N],v[N],m;
 7 int find(int x){
 8     if(fa[x]==x)return x;
 9     fa[x]=find(fa[x]);
10     v[fa[x]]|=v[x];
11     return fa[x];
12 }
13 int main(){
14     scanf("%d%d",&n,&m);
15     for(int i=1;i<=n;i++)fa[i]=i;
16     int x,y;
17     for(int i=1;i<=m;i++){
18         scanf("%d%d",&x,&y);
19         int dx=find(x),dy=find(y);
20         if(dx==dy){
21             v[x]=1;v[y]=1;
22         }else{
23             fa[dx]=dy;
24         }
25     }
26     for(int i=1;i<=n;i++)find(i);
27     for(int i=1;i<=n;i++)if(fa[i]==i&&v[i]==0){
28         puts("NIE");return 0;
29     }puts("TAK");
30 }
View Code

 

[Poi2010]Guilds

题意:给一张无向图,要求你用黑白给点染色,且满足对于任意一个黑点,至少有一个白点和他相邻;对于任意一个白点,至少有一个黑点与他相邻,问能否成功。

分析:判断一下是否有孤立的点就行。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 #define N 200020
 6 #define M 1200010
 7 int head[N],to[M],nxt[M],cnt,n,m,tag[N];
 8 inline void add(int u,int v){
 9     to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;   
10 }
11 int main(){
12     scanf("%d%d",&n,&m);
13     int x,y;
14     for(int i=1;i<=m;++i){
15         scanf("%d%d",&x,&y);
16         add(x,y);add(y,x);
17     }
18     for(int i=1;i<=n;++i){
19         if(!tag[i])tag[i]=2;
20         int f=0;
21         for(int j=head[i];j;j=nxt[j]){
22             f=1;
23             if(!tag[to[j]]){
24                 tag[to[j]]=3-tag[i];    
25             } 
26         }
27         if(!f){puts("NIE");return 0;}
28     }
29     printf("TAK\n");
30 }
View Code

 

[POI2009]Tab

题意:2个n*m矩阵,保证同一个矩阵中元素两两不同。问能否通过若干次交换两行或交换两列把第一个矩阵变成第二个。

分析:我们发现不论是交换行还是交换列,每行每列出现的数字都是不变的,存一下每个点对应的行列直接找就行。

注意可能是负数。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 #define N 1000000
 6 int P[2000020][2];
 7 int a[1010][1010];
 8 int n,m,T;
 9 int main(){
10     scanf("%d",&T);
11     int x;
12     while(T--){
13         scanf("%d%d",&n,&m);
14         for(int i=1;i<=n;i++){
15             for(int j=1;j<=m;j++){
16                 scanf("%d",&x);
17                 P[x+N][0]=i;
18                 P[x+N][1]=j;
19             }
20         }
21         int f=0;
22         for(int i=1;i<=n;i++){
23             for(int j=1;j<=m;j++){
24                 scanf("%d",&a[i][j]);
25                 if(P[a[i][j]+N][0]!=P[a[i][1]+N][0]||P[a[i][j]+N][0]==0)f=1;
26                 if(P[a[i][j]+N][1]!=P[a[1][j]+N][1]||P[a[i][j]+N][1]==0)f=1;
27             }
28         }
29         puts(f?"NIE":"TAK");
30         memset(P,0,sizeof(P));
31     }
32 }
33 
View Code

 

[POI2008]砖块Klo

题意:N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.

分析:维护一个支持插入和删除操作能求中位数的数据结构。平衡树和对顶堆均可。

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include <queue>
 5 using namespace std;
 6 priority_queue<int, vector<int>,less<int> >p;
 7 priority_queue<int, vector<int>,greater<int> >q;
 8 #define N 100050
 9 #define LL long long
10 int n,k,a[N],L,R,key,lz[N*12],sip,siq;
11 LL sup,suq,ans;
12 void pud(){
13     if(!p.empty()){
14         while(lz[p.top()]&&!p.empty()){
15             lz[p.top()]--;p.pop();
16         }
17     }
18     if(!q.empty()){
19         while(lz[q.top()]&&!q.empty()){
20             lz[q.top()]--;q.pop();
21         }
22     }
23 }
24 void add(int x){
25     pud();  
26     while(sip<(k+1)/2&&siq){
27         int t=q.top();q.pop();
28         p.push(t);
29         sip++;siq--;
30         suq-=t;sup+=t;
31         pud();
32     }
33     if(sip==0){
34         sip++;
35         sup+=x;
36         p.push(x);return ;
37     }
38     pud();
39     if(x<p.top()){
40         sip++;
41         sup+=x;
42         p.push(x);
43     }else{
44         siq++;
45         suq+=x;
46         q.push(x);
47     }
48     pud();
49     while(sip>(k+1)/2&&sip){
50         int t=p.top();p.pop();
51         q.push(t);
52         sip--;siq++;
53         suq+=t;sup-=t;
54         pud();
55     }
56     pud();
57     while(sip<(k+1)/2&&siq){
58         int t=q.top();q.pop();
59         p.push(t);
60         sip++;siq--;
61         suq-=t;sup+=t;
62         pud();
63     }
64     pud();
65 }
66 void del(int x){
67     lz[x]++;
68     if(x>p.top())siq--,suq-=x;
69     else sip--,sup-=x;
70     pud();
71 }
72 int main(){
73     scanf("%d%d",&n,&k);
74     for(int i=1;i<=n;i++){
75         scanf("%d",&a[i]);
76     }
77     for(int i=1;i<=k;i++){
78         add(a[i]);
79     }
80     int mid=p.top();
81     L=1,R=k,ans=1ll*(k+1)/2*mid-sup+suq-1ll*k/2*mid,key=mid;
82     for(int i=k+1;i<=n;i++){
83     pud();
84         del(a[i-k]);
85     pud();
86         add(a[i]);
87         mid=p.top();
88         if(ans>=1ll*(k+1)/2*mid-sup+suq-1ll*k/2*mid&&1ll*(k+1)/2*mid-sup+suq-1ll*k/2*mid>=0){
89             ans=1ll*(k+1)/2*mid-sup+suq-1ll*k/2*mid;
90             L=i-k+1;R=i;key=mid;
91         }
92     }
93     printf("%lld\n",ans);
94     for(int i=1;i<=n;i++){
95         if(i>=L&&i<=R)printf("%d\n",key);
96         else printf("%d\n",a[i]);
97     }
98 }
View Code

 

[Poi2010]Pilots

题意:给一个数列,求一个最长的子段,子段内任意两元素之差不大于k

分析:单调队列。用两个单调队列存一下最大,最小值。每次求出当前能使得子段合法的最左边的下标,更新答案。

代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 3000050
int n,a[N],Q1[N],l1,r1,k,ans;
int Q2[N],l2,r2;
char nc(){
    static char buf[100000], *p1, *p2;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
int rd(){
    int x=0;char s=nc();
    while(s<'0'||s>'9')s=nc();
    while(s>='0'&&s<='9')x=x*10+s-48,s=nc();
    return x;
}
int main(){
    k = rd();
    n = rd();
    int i, now = 1;
    for(i = 1;i <= n; i++){
        a[i] = rd();
        while(l1 < r1 && a[i] <= a[Q1[r1 - 1]]) r1--;
        while(l2 < r2 && a[i] >= a[Q2[r2 - 1]]) r2--;
        Q1[r1++] = i;
        Q2[r2++] = i;
        while(l1 < r1 && l2 < r2 && a[Q2[l2]] - a[Q1[l1]] > k) {
            if(Q2[l2] > Q1[l1]){
                now = Q1[l1] + 1;
                l1++;
            }else{
                now = Q2[l2] + 1;
                l2++;
            }
        }
        ans = max(ans, i - now + 1);
    }
    printf("%d\n", ans);
}

 [Poi2014]Couriers

http://www.cnblogs.com/suika/p/8594235.html

[POI2007]立方体大作战tet

题意:给定一个长度为 $2n$ 的序列,$1$ ~ $n$ 各出现两次,可以交换相邻两项,两个同样的数放在一起会对消,求把所有数对消的最小交换次数。

分析:设两个数 $AB$ ,考虑它们的可能的排列:$AABB$ . $ABBA$ . 这两种情况在最优解中 $AB$ 之间一定不会发生交换。发生交换的只可能是 $ABAB$ 这种,并且可以发现每次操作都会把 $ABAB$ 这种情况变成不需要交换的另两种情况,也就是说,答案 = 所有 $ABAB$ 这种情况的个数。我们可以 $n^2$ 枚举找一下这种情况。具体地,我们扫到一个数,如果这个数以前没有出现过,则在数的位置上 $+1$ ,否则,在这个数第一次出现的位置到当前位置开始,求这段区间和并加到 $ans$ 中,然后在第一次出现的位置上 $-1$ 。

用树状数组优化一下即可。

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 1000500
#define LL long long
LL ans,c[N],a[N],n,pos[N];
void fix(int x,int v)
{
	for(;x<=n+n;x+=x&(-x)) c[x]+=v;
}
LL inq(int x)
{
	LL re=0;
	for(;x;x-=x&(-x)) re+=c[x];
	return re;
}
int main()
{
	//freopen("Rumia.in","r",stdin);
	//freopen("Rumia.out","w",stdout);
	scanf("%lld",&n);
	int i,x;
	for(i=1;i<=n+n;i++)
	{
		scanf("%d",&x);
		if(pos[x]==0)
		{
			pos[x]=i;
			fix(i,1);
		}
		else{
			ans+=inq(i-1)-inq(pos[x]);fix(pos[x],-1);
		}
	}
	printf("%lld\n",ans);
}
/*
5
5 2 3 1 4 1 4 3 5 2
*/

 [POI2004]PRZ:

http://www.cnblogs.com/suika/p/8551872.html

[Poi2011]Strongbox:

题意:有一个密码箱,0到n-1中的某些整数是它的密码。
且满足,如果a和b都是它的密码,那么(a+b)%n也是它的密码(a,b可以相等)
某人试了k次密码,前k-1次都失败了,最后一次成功了。
问:该密码箱最多有多少不同的密码。

分析:可以证明密码一定是一定有一个最小的间隔,且这个最小间隔一定是$gcd(n,k)$的约数。然后枚举约数判断是否可以。

但还是容易T,发现gcd(n,a[i])有很多相同的值,于是去重后A了。

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
typedef long long ll;
ll gcd(ll x,ll y) {
    return y?gcd(y,x%y):x;
}
ll n,k,a[250050];
char nc() {
    static char buf[100000],*p1,*p2;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline ll rd() {
    register ll x=0; register char s=nc();
    while(s<'0'||s>'9')s=nc();
    while(s>='0'&&s<='9')x=x*10+s-'0',s=nc();
    return x;
}
inline bool check(ll x) {
    register int i;
    for(i=1;i<=k;i++) if(a[i]%x==0) return 0;
    return 1;
}
int main() {
    n=rd(); k=rd();
    register int i;
    for(i=1;i<=k;i++) {
        a[i]=rd(); a[i]=gcd(a[i],n);
    }
    ll base=a[k];
    sort(a+1,a+k); k=unique(a+1,a+k)-a-1;
    int b=ceil(sqrt(base));
    ll ans=0;
    for(i=1;i<=b;i++) {
        if(base%i==0) {
            if(check(i)) {printf("%lld\n",n/i);return 0;}
            else if(check(base/i)) ans=n/(base/i);
        }
    }
    printf("%lld\n",ans);
}

 [Poi2012]Letters:

直接求逆序对即可。

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 1000050
#define LL long long
char s1[N],s2[N];
int a[N],b[N],n,pos[30],ch[30][100050];
LL c[N],ans;
LL inq(int x)
{
    LL re=0;
    for(;x;x-=x&(-x)) re+=c[x];
    return re;
}
void fix(int x,LL v)
{
    for(;x<=n;x+=x&(-x)) c[x]+=v;
}
int main()
{
    scanf("%d%s%s",&n,s1+1,s2+1);
    int i;
    for(i=1;i<=n;i++) a[i]=s1[i]-'A'+1, b[i]=s2[i]-'A'+1,ch[a[i]][++ch[a[i]][0]]=i;
    for(i=1;i<=n;i++) pos[b[i]]++,b[i]=ch[b[i]][pos[b[i]]];
    for(i=n;i;i--) ans+=inq(b[i]),fix(b[i],1);
    printf("%lld\n",ans);
}

 [Poi2012]Well:

http://www.cnblogs.com/suika/p/8888728.html

[Poi1999]洞穴攀行:

裸的最大流

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define inf 100000000
#define N 250
#define M 100050
#define S (1)
#define T (n)
int n,head[M],to[M],nxt[M],cnt=1,flow[M];
int Q[N],l,r,dep[N];
inline void add(int u,int v,int f) {
    to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;flow[cnt]=f;
}
bool bfs() {
    int i,x;
    l=r=0;
    memset(dep,0,sizeof(dep));
    dep[S]=1;
    Q[r++]=S;
    while(l<r) {
        x=Q[l++];
        for(i=head[x];i;i=nxt[i]) {
            if(!dep[to[i]]&&flow[i]) {
                dep[to[i]]=dep[x]+1;
                if(to[i]==T) return 1;
                Q[r++]=to[i];
            }
        }
    }
    return 0;
}
int dfs(int x,int mf) {
    if(x==T)return mf;
    int nf=0,i;
    for(i=head[x];i;i=nxt[i])if(dep[to[i]]==dep[x]+1&&flow[i]) {
        int tmp=dfs(to[i],min(flow[i],mf-nf));
        nf+=tmp;
        flow[i]-=tmp;
        flow[i^1]+=tmp;
        if(nf==mf) break;
    }
    dep[x]=0;
    return nf;
}
void dinic() {
    int f,ans=0;
    while(bfs()) while(f=dfs(S,inf)) ans+=f;
    printf("%d\n",ans);
}
int main() {
    scanf("%d",&n);
    int i,x,y;
    for(i=1;i<n;i++) {
        scanf("%d",&x);
        while(x--) {
            scanf("%d",&y);
            if(i==S || y==T) {
                add(i,y,1);
            }else add(i,y,inf);
            add(y,i,0);
        }
    }
    dinic();
}

 [Poi2000]病毒:

http://www.cnblogs.com/suika/p/8891891.html

Poi2013 Bytecomputer:

http://www.cnblogs.com/suika/p/8678279.html

[POI2015]Kinoman:

http://www.cnblogs.com/suika/p/8893959.html

剩下的以及以后的POI题都单独更吧,这太长了。

posted @ 2018-02-11 12:17  fcwww  阅读(1009)  评论(0编辑  收藏  举报