20170612测试

问题 A: 装果子

时间限制: 1 Sec  内存限制: 128 MB
提交: 96  解决: 54

题目描述

果园里有n颗果树,每棵果树都有一个编号i(1≤in)。小明已经把每棵果树上的果子都摘下来堆在了这棵树的下方,每棵树下方的果子体积为ai

现在小明将拿来m个袋子把这些果子都装进袋子里。每个袋子的体积为v。小明会按照如下规则把果子装进袋子里:

(a)从第1棵果树开始装起,由1到n一直装到第n棵果树。

(b)如果这棵果树下的果子能全部装进当前这个袋子,就装进去;如果不能,就关上当前这个袋子,打开一个新的袋子开始装。

小明希望在能把所有果子都装进袋子里的前提下,v尽量小。m个袋子并不一定都要装进果子。

输入

输入文件名为fruit.in

输入第1行,包含两个整数nm

第2行,包含n个整数ai

输出

输出文件名为fruit.out

输出仅1行,表示最小的v

样例输入

fruit.in
3 3
1 2 3
fruit.out
3
fruit.in
5 3
1 3 6 1 7
fruit.out
7
fruit.in
6 3
1 2 1 3 1 4
fruit.out
4

样例输出

【输入输出样例解释1】 每个袋子的体积为3即可。前2棵果树的果子装在第一个袋子里,第3棵果树的果子装在第二个袋子里。第三个袋子不用装了。 【输入输出样例解释2】 每个袋子的体积为7即可。前2棵果树的果子装在第一个袋子里,此时第一个袋子已经装了4单位体积的果子,第3棵果树的果子装不下了,所以装进第二个袋子里,第4棵果树的果子刚好装进第二个袋子,第5棵果树的果子装进第三个袋子里。 【输入输出样例解释3】 每个袋子的体积为4即可。前3棵果树的果子装在第一个袋子里,第4~5棵果树的果子装在第二个袋子里,第6棵果树的果子装在第三个袋子里。

提示

【数据范围】


对于40%的数据,0<mn≤1,000,0<ai≤1,000;


对于70%的数据,0<mn≤100,000,0<ai≤100,000;


对于100%的数据,0<mn≤100,000,0<ai≤1,000,000,000。

裸裸的二分:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define ll long long
 5 using namespace std;
 6 int a[100005];
 7 int n,m; 
 8 bool check(ll x){
 9     ll v=x; int nu=1;
10     for (int i=1;i<=n;i++)
11         if (v>=(ll)a[i]) v-=(ll)a[i];
12         else v=x-(ll)a[i],nu++;
13     if (nu<=m) return 1;
14     return 0;
15 }
16 int main(){
17     ll sum=0,Max=0;
18     scanf("%d%d",&n,&m);
19     for (int i=1;i<=n;i++){
20         scanf("%d",&a[i]);
21         sum+=(ll)a[i];
22         Max=max(Max,(ll)a[i]);
23     }
24     ll l=Max,r=sum;
25     while (l<r){
26         ll mid=(l+r)>>1;
27         if (check(mid)) r=mid;
28         else l=mid+1;
29     }
30     printf("%lld",l);
31     return 0;
32 }
View Code

问题 B: 零件加工

时间限制: 1 Sec  内存限制: 128 MB
提交: 107  解决: 46

题目描述

工匠小K最近有n个零件需要加工。每个零件都需要ti天的时间来完成,每个零件每延迟一天加工都要缴纳一定的罚金si。延迟的天数为从今天算起到该工作开始的那天,第一个零件加工没有罚金。现在小K想知道怎样安排加工顺序可以使他要交的罚金最少,最少是多少。

这个数可能会很大,请输出这个数对m取模后的结果。

输入

输入文件名为process.in

输入第一行为一个整数n,表示需要加工的零件总数。

第二行为一个整数m,表示答案要对m取模。

第3~n+2行,每行两个整数tisi

输出

输出文件名为process.out

输出仅一行,一个整数,表示小K最少要缴纳的罚金对m取模的结果。

样例输入

process.in
2
100
2 33
33 2
process.out
4
process.in
4
100
3 3
6 4
2 2
8 5
process.out
81

样例输出

【输入输出样例解释1】 先加工第一个,需要2天时间,再加工第二个。需要缴纳的罚金为2×2=4。 【输入输出样例解释2】 如果按照1→2→3→4的顺序进行加工,需要缴纳的罚金为0×3+3×4+(3+6)×2+ (3+6+2)×5=85; 最佳方案是3→1→2→4,此时需要缴纳的罚金为0×2+2×3+(2+3)×4+(2+3+6)×5=81。

提示

【数据范围】

对于40%的数据,0<n≤10,000,0<ti,si≤10,000; 

对于80%的数据,0<n≤100,000,0<ti,si≤2×10^9,0<m≤10^8; 

对于100%的数据,0<n≤100,000,0<ti,si≤2×10^9,0<m≤10^18。

 贪心,按照t/s升序排序然后计算。 

解题关键是以状态下相邻两个的选择。

详细证明见HK

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=1000000007;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll mul(ll a,ll b,ll pp){ll ans=0;for(;b;b>>=1,a=mo(a+a,pp))if(b&1)ans=mo(ans+a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; }
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
32 ll read(){ ll ans=0; char last=' ',ch=getchar();
33 while(ch<'0' || ch>'9')last=ch,ch=getchar();
34 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
35 if(last=='-')ans=-ans; return ans;
36 }
37 #define N 100005
38 struct node{
39     ll t,s;
40 }f[N];
41 bool cmp(node a,node b){
42     return b.s*a.t<a.s*b.t;
43 }
44 int main()
45 {
46     int n=read(); ll m=read(),sum=0,ans=0;
47     for (int i=1;i<=n;i++) f[i].t=read(),f[i].s=read();
48     sort(f+1,f+n+1,cmp);
49     for (int i=1;i<=n;i++){
50         ans=mo(ans+mul(f[i].s,sum,m),m);
51         sum=mo(sum+f[i].t,m);
52     }
53     printf("%lld",mo(ans,m));
54     return 0;
55 }
View Code

问题 C: 种树

时间限制: 2 Sec  内存限制: 128 MB

题目描述

为了绿化乡村,H村积极响应号召,开始种树了。

H村里有n幢房屋,这些屋子的排列顺序很有特点,在一条直线上。于是方便起见,我们给它们标上1~n。树就种在房子前面的空地上。

同时,村民们向村长提出了m个意见,每个意见都是按如下格式:希望第li个房子到第ri个房子的房前至少有ci棵树。

因为每个房屋前的空地面积有限,所以每个房屋前最多只能种ki棵树。

村长希望在满足村民全部要求的同时,种最少的树以节约资金。请你帮助村长。

输入

输入文件名为tree.in

输入第1行,包含两个整数nm

第2行,有n个整数ki

第2~m+1行,每行三个整数lirici

输出

输出文件名为tree.out

输出1个整数表示在满足村民全部要求的情况下最少要种的树。村民提的要求是可以全部满足的。

样例输入

tree.in
5 3
1 1 1 1 1
1 3 2
2 4 2
4 5 1
tree.out
3
tree.in
4 3
3 2 4 1
1 2 4
2 3 5
2 4 6
tree.out
8

样例输出

【输入输出样例解释1】 如图是满足样例的其中一种方案,最少要种3棵树。 【输入输出样例解释2】 如图是满足样例的其中两种方案,左图的方案需要种9棵树,右图的方案需要种8棵树。可以验证,最少需要种8棵树。

提示

【数据范围】


对于30%的数据,0<n≤100,0<m≤100,ki=1;


对于50%的数据,0<n≤2,000,0<m≤5,000,0<ki≤100;


对于70%的数据,0<n≤50,000,0<m≤100,000,0<ki≤1,000;


对于100%的数据,0<n≤500,000,0<m≤500,000,0<ki≤5,000

法一差分约束:

开一个s数组记录前缀和。 
根据题意我们可以得到3个约束条件: 
s[r]-s[l-1]≥c,① 
s[i]≥s[i-1],② 
s[i]-s[i-1]≤k,③ 
根据①得s[l]-s[r]≤-c,在r和l-1之间连一条权值为-c的边。 
根据②得s[i-1]-s[i]≤0,在i和i-1之间连一条权值为0的边。 
根据③在i-1和i之间连一条权值为k的边。 
50分算法:Bellman-Ford。 
时间复杂度:O(nm) 
70分算法:SPFA。 
时间复杂度:O(km) 
100分算法: 
观察到最大可能需要连150w条边,因此我们要考虑有些边是否需要连。 
我们可以只根据条件①计算,每次更新后O(n)检查是否满足条件②和③,如果不满足就修改,这样只用连50w条边,可以过全部数据。 
Tip:事实上SPFA可以过100%

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<ll,ll> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 ld eps=1e-9;
25 ll pp=1000000007;
26 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
27 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
28 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
29 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; }
30 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
31 ll read(){ ll ans=0; char last=' ',ch=getchar();
32 while(ch<'0' || ch>'9')last=ch,ch=getchar();
33 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
34 if(last=='-')ans=-ans; return ans;
35 }
36 #define N 500005
37 #include<queue>
38 const ll inf=1e15;
39 vector<pr> vec[N];
40 ll dis[N];
41 bool v[N];
42 void spfa(int x){
43     for (int i=0;i<N;i++) dis[i]=inf,v[i]=0;
44     dis[x]=0; v[x]=1;
45     queue<int> q; q.push(x);
46     while (!q.empty()){
47         int u=q.front(); q.pop(); v[u]=0;
48         for (int i=0;i<vec[u].size();i++){
49             int v_=vec[u][i].fi,c=vec[u][i].sc; 
50             if (dis[v_]>dis[u]+c){
51                 dis[v_]=dis[u]+c;
52                 if (!v[v_]) q.push(v_),v[v_]=1;
53             }
54         }
55     }
56 }
57 int main(){
58     int n=read(),m=read();
59     for (int i=1;i<=n;i++){
60         int k=read();
61         vec[i-1].pb(mp(i,k));
62         vec[i].pb(mp(i-1,0));
63     }
64     for (int i=1;i<=m;i++){
65         int a=read(),b=read(),c=read();
66         vec[b].pb(mp(a-1,-c));
67     }
68     spfa(n);
69     printf("%lld",-dis[0]);
70     return 0;
71 } 
View Code

法二贪心:

题目中要求要种树种得少,就要使一棵树给多个区间使用,这样,尽量在重叠区间种树即可,而重叠位置一定是区间尾部。处理问题时,先按所有区间的结束位置排序,若结束位置相同,则按开始位置从大到小排序。之后依次处理每个区间,先在第一个区间尾部种满足要求的树,对下一个区间,看差多少棵就在该区间尾部种多少。 
【算法步骤】: 
1.先快排 
2.对每个区间依次处理 
a.从前到后扫描这个区间,统计点的个数; 
b.若点的个数超过了要求的点数,则continue; 
c.从该区间后向前扫描,添加覆盖点。 
3.输出ans 
Tip:这种方法只适用于小数据,对于大数据我们可以用树状数组加快求和,即过程a,还可以用并查集的方法来加速种树过程c,当有一段区间的树种满时把它与前一个区间合并就行了。

还是考虑一下 (FROM Lhq)

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=1000000007;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; }
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
32 ll read(){ ll ans=0; char last=' ',ch=getchar();
33 while(ch<'0' || ch>'9')last=ch,ch=getchar();
34 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
35 if(last=='-')ans=-ans; return ans;
36 }
37 #define N 500000
38 #define lowbit(i) (i&(-i))
39 struct node{
40     int a,b; ll v;
41 }f[N+5];
42 ll T[N+5],k[N+5],fl[N+5]; ll ans;
43 void add(int a,int b){
44     for (int i=a;i<=N;i+=lowbit(i)) T[i]+=b;
45 }
46 ll sum(int a){
47     ll Sum=0;
48     for (int i=a;i>0;i-=lowbit(i)) Sum+=T[i];
49     return Sum;
50 }
51 bool cmp(node a,node b){
52     return a.b<b.b||a.b==b.b&&a.a<a.b;
53 }
54 int main(){
55     int n=read(),m=read();
56     for (int i=1;i<=n;i++) k[i]=read();
57     for (int i=1;i<=m;i++) {
58         f[i].a=read(); f[i].b=read(); f[i].v=read(); 
59     }
60     sort(f+1,f+m+1,cmp);
61     for (int i=1;i<=m;i++){
62         ll Sum=sum(f[i].b)-sum(f[i].a-1);
63         if (f[i].v>Sum){
64             int j=f[i].b; 
65             while (Sum<f[i].v){
66                 if (fl[j]>0) j=fl[j]; 
67                 if (f[i].v>=Sum+k[j]){
68                     Sum+=k[j]; ans+=k[j]; add(j,k[j]); k[j]=0; j--; 
69                 } else {
70                     ans+=f[i].v-Sum; add(j,f[i].v-Sum); k[j]-=f[i].v-Sum; Sum=f[i].v;
71                 }
72             }
73             fl[f[i].b]=j;
74         }
75         //cout<<i<<" "<<ans<<endl;
76     } 
77     printf("%lld",ans);
78     return 0;
79 }
View Code

问题 D: 完全平方数

时间限制: 1 Sec  内存限制: 128 MB
提交: 74  解决: 36

题目描述

一个数如果是另一个整数的完全平方,那么我们就称这个数为完全平方数(Pefect Sqaure),也称平方数。

小A认为所有的平方数都是很perfect的~

于是他给了小B一个任务:用任意个不大于n的不同的正整数相乘得到完全平方数,并且小A希望这个平方数越大越好。

请你帮助小B告诉小A满足题意的最大的完全平方数。

输入

输入文件名为number.in 

 

输入仅 1行,一个数n

 

输出

输出文件名为number.out

输出仅1行,一个数表示答案。由于答案可以很大,所以请输出答案对100000007取模后的结果。

样例输入

【输入输出样例1】
number.in
7
number.out
144
【输入输出样例解释1】
144=2×3×4×6,是12的完全平方。

样例输出

【输入输出样例2】
number.in
9
number.out
5184
【输入输出样例解释2】
5184=3×4×6×8×9,是72的完全平方。

提示

【数据范围】


对于20%的数据,0<n≤100;


对于50%的数据,0<n≤5,000;


对于70%的数据,0<n≤100,000;


对于100%的数据,0<n≤5,000,000。

 数的阶乘中所有质因数的幂数整除2*2;

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 const int pp=100000007;
 6 #define ll long long
 7 long long Ans=1LL;
 8 #define N 5000005
 9 int pr[N],f[N];
10 ll q(ll a,ll b){
11     ll ans=1LL; for (;b;b>>=1,a=(a*a)%pp) if (b&1) ans=(ans*a)%pp; return ans;
12 }
13 int main(){ 
14     int n,nu=0; scanf("%d",&n);
15     for (int i=2;i<=n;i++){
16         if (!f[i]) pr[++nu]=i;
17         for (int j=1;j<=nu && pr[j]*i<=n;j++){
18             f[pr[j]*i]=1;
19             if (i%pr[j]==0) break;
20         }  
21     }
22     for (int i=1;i<=nu;i++){
23         ll x=(ll)pr[i],ans=0LL;
24         while (x<=(ll)n){
25             ans+=((ll)n/x);
26             x*=(ll)pr[i];
27         }
28         Ans=(Ans*q((ll)pr[i],ans>>1))%pp;
29     }
30     printf("%lld",q(Ans,2));
31     return 0;
32 }
View Code

问题 E: 卡片游戏

时间限制: 1 Sec  内存限制: 128 MB
提交: 50  解决: 21

题目描述

小D举办了元旦联欢活动,其中有一个卡片游戏。

游戏的规则是这样的:有n张卡片,每张卡片上正面写着一个小于等于100的正整数ai,反面都是一样的花色。这n张卡片正面朝下叠成一堆,玩这个游戏的人从中可以抽出连续的k(1≤kn)张卡片。如果对于这k张卡片上的数字的平均值a,满足l<=a<=r,那他就可以获得小礼物一件。

小W来玩这个游戏了,她事先通过某些途径知道了这n张卡片上写的数字,现在她想知道她获得小礼物的期望值。

小W对小数很头疼,所以请你用分数的形式告诉她答案。

输入

输入文件名为game.in

输入第1行,三个整数nlr

第2行,包含n个整数ai

输出

输出文件名为game.out

输出仅1行,表示小W获得小礼物的期望值。输出格式为“P/Q”(PQ互质)。如果期望值是01就不用输出分数了

样例输入

game.in
4 2 3
3 1 2 4
game.out
7/10

样例输出

【输入输出样例2】
game.in
4 1 4
3 1 2 4
game.out
1

提示

【输入输出样例解释1】



【输入输出样例解释1】抽出的卡片


a(保留2位小数)


是否满足l<=a<=r



3


3.00




1


1.00


2


2.00




4


4.00


3,1


2.00




1,2


1.50


2,4


3.00




3,1,2


2.00




1,2,4


2.33




3,1,2,4


2.50




 【输入输出样例解释2】


由上表得,小W总是可以获得小礼物。因此期望值是1


 


【数据范围】


对于30%的数据,0<n≤10,000;


对于70%的数据,0<n≤100,000;


对于100%的数据,0<n≤500,000,0<l<r≤100。


由表可得,一共有10种情况,其中有7种情况小W可以获得小礼物。因此小W获得小礼物的期望值是7/10。

 数学推:

T2-1 
T2-2

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=1000000007;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; }
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
32 ll read(){ ll ans=0; char last=' ',ch=getchar();
33 while(ch<'0' || ch>'9')last=ch,ch=getchar();
34 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
35 if(last=='-')ans=-ans; return ans;
36 }
37 #define N 500005
38 ll gcd(ll a,ll b){
39     return (b==0)?a:gcd(b,a%b); 
40 }
41 ll cnta,cntb;
42 int a[N],b[N],c[N],sum[N]; 
43 void mega(int l,int r){
44     int mid=(l+r)>>1,i=l,j=mid+1,k=0;
45     while (i<=mid && j<=r){
46         while (a[i]<a[j] && i<=mid){
47             c[++k]=a[i]; i++;
48         }
49         while(a[i]>=a[j] && j<=r){
50             c[++k]=a[j]; j++; cnta+=(ll)(mid-i+1); 
51         }
52     } 
53     while (i<=mid) c[++k]=a[i],i++;
54     while (j<=r) c[++k]=a[j],j++; 
55     for (int i=1;i<=k;i++)
56         a[i+l-1]=c[i];
57 }
58 void megb(int l,int r){
59     int mid=(l+r)>>1,i=l,j=mid+1,k=0;
60     while (i<=mid && j<=r){
61         while (b[i]<=b[j] && i<=mid){
62             c[++k]=b[i]; i++;
63         }
64         while(b[i]>b[j] && j<=r){
65             c[++k]=b[j]; j++; cntb+=(ll)(mid-i+1); 
66         }
67     } 
68     while (i<=mid) c[++k]=b[i],i++;
69     while (j<=r) c[++k]=b[j],j++; 
70     for (int i=1;i<=k;i++)
71         b[i+l-1]=c[i];
72 }
73 void msort(int l,int r){
74     if (l==r) return;
75     int mid=(l+r)>>1;
76     msort(l,mid);
77     msort(mid+1,r);
78     mega(l,r);
79     megb(l,r);
80 }
81 int main(){
82     int n=read(),l=read(),r=read(); 
83     for (int i=1;i<=n;i++) {
84         int a_=read();
85         sum[i]=sum[i-1]+a_;
86         a[i]=l*i-sum[i];
87         b[i]=r*i-sum[i];
88     }
89     msort(0,n);
90     ll B=(ll)n*((ll)n+1LL)/2LL;
91     ll A=cnta-cntb;
92     ll C=gcd(A,B);
93     if (A==0) printf("0");
94     else if (A==B) printf("1"); 
95     else printf("%lld/%lld",A/C,B/C);
96     return 0;
97 }
View Code

问题 F: 围栏问题

时间限制: 2 Sec  内存限制: 128 MB
提交: 43  解决: 23

题目描述

在一片草原上,有n只兔子无忧无虑地生活着。这片草原可以划分成m×m的方阵。每个方格内最多有一只兔子。

一位饲养员负责喂养这些兔子。为了方便,她需要用篱笆建造最多k座围栏,将草原上的兔子全部围起来。

围栏需要满足以下条件:

(1)必须沿着网格线建造;

(2)每座围栏是一个不与自身重叠或相交的封闭回路;

(3)各座围栏之间互相不重叠、不相交;

(4)一座围栏不能被围在另一座围栏里面。

请你帮助饲养员计算一下围栏总长度的最小值。

输入

输入文件名为fence.in

输入第1行为三个整数mkn

接下来n行每行为一对正整数xy,表示第x行第y列的方格中有一只兔子。

输出

输出文件名为fence.out

输出仅1行,为一个正整数,表示围栏总长度的最小值。

样例输入

【输入输出样例1】
fence.in
6 1 4
1 3
4 2
4 4
6 4
fence.out
18

样例输出

【输入输出样例2】
fence.in
6 2 4
1 3
4 2
4 4
6 4
fence.out
16

提示

【数据范围】


对于10%的数据,k=1;


对于10%~30%的数据,k=2;


对于30%~60%的数据,n≤10;


对于100%的数据,1≤k≤n≤16,m≤1,000。

首先,两个围栏互相包含的情况不可能在最优解中出现(把里面那个拆掉可以节省篱笆,得到一个更优解)。 
其次,两个围栏相交的情况也一定不是最优,如下图所示,把重叠的部分拆掉可以得到更优解。 
T3-1 
由于我们的目标是最小化周长,可以得到这样一条重要性质:矩形的围栏比不规则形状的更优。如图,把里面的边往外平移,成为一个矩形的边框,这样可以在周长不变的情况下,围住更多的土地。(不用担心扩展出去的部分会和另外的围栏相交,因为这不可能在最优解中出现,刚才已经提到) 
T3-2 
有些情况下,矩形边框不仅扩大围住的范围而且能节省周长。 
T3-3 
所以,接下来我们只需考虑用矩形去包围兔子就够了。 
T3-4 
定义基本矩形或叫极小矩形——假如这个矩形再往里缩小一点就会有兔子从里面逃出。 
T3-5 
如就不是一个极小矩形,它可以往里收缩

现在它是一个极小矩形。 
容易发现,最优解中必然只包含极小矩形。 


解法一: 
搜索+剪枝,枚举每一个兔子所在的栅栏,如果还可以再多一种栅栏就可以多一种选择:即开一个刚刚包围自己的栅栏。另一种选择就是和之前的某一个集合的兔子合并放到一个栅栏里,计算周长时找到上下左右的最大差值,记得+1。

解法二: 
我们可以预处理出所有极小矩形:枚举所有兔子的非空子集,找出这个子集中最上、最左、最右、最下的兔子,就可得到一个极小矩形。(当然这样计算会出现许多重复的,剔除即可)。这种做法虽然是指数级的但是编码简单,而且n很小,仍可接受。 
现在我们有了一堆矩形,对于每个矩形我们掌握它的两个属性:周长、围住了的兔子集合。问题转化为:从这堆矩形中选出不超过k个,在满足这些兔子集合互不相交,且其并集恰好是兔子全集的条件下,最小化总周长。 
这是一个典型的精确覆盖问题,搜索解决即可。可以使用二进制来表示各个集合,用位运算的方法达到优化的效果。也可以用DLX来做,更快,更爽。 

只有解法一,法二不会(┭┮﹏┭┮):

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=1000000007;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; }
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
32 ll read(){ ll ans=0; char last=' ',ch=getchar();
33 while(ch<'0' || ch>'9')last=ch,ch=getchar();
34 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
35 if(last=='-')ans=-ans; return ans;
36 }
37 const int N=20;
38 int x[N],y[N],n,m,k;
39 int lx[N],ly[N],rx[N],ry[N],ans=1e09;
40 void dfs(int x_,int y_,int z)
41 {
42     if(z>ans) return;
43     if(x_>n) { ans=z; return; }
44     if(y_<k){
45         rx[y_+1]=lx[y_+1]=x[x_]; ry[y_+1]=ly[y_+1]=y[x_];
46         dfs(x_+1,y_+1,z+4);
47         rx[y_+1]=lx[y_+1]=0; ry[y_+1]=ly[y_+1]=0;
48     }
49     int ax,ay,bx,by,nz;
50     for(int i=1;i<=y_;i++)
51     {
52         ax=lx[i]; ay=ly[i];
53         bx=rx[i]; by=ry[i];
54         nz=z-2*((bx-ax+1)+(by-ay+1));
55         lx[i]=min(x[x_],lx[i]); rx[i]=max(x[x_],rx[i]);
56         ly[i]=min(y[x_],ly[i]); ry[i]=max(y[x_],ry[i]);
57         nz+=2*((rx[i]-lx[i]+1)+(ry[i]-ly[i]+1));
58         dfs(x_+1,y_,nz);
59         lx[i]=ax; ly[i]=ay;
60         rx[i]=bx; ry[i]=by;
61     }
62 }
63 int main()
64 {
65     m=read(),k=read(),n=read();
66     for(int i=1;i<=n;i++) x[i]=read(),y[i]=read();
67     dfs(1,0,0);
68     printf("%d
",ans);
69     return 0;
70 }
View Code
原文地址:https://www.cnblogs.com/SXia/p/7123301.html