【寒假集训系列2.15】

得分100+100+20=220

其实估分是100+60+10=170啊

T1:地平线

 

题目描述:

老胡带着奶牛去都市观光。在落日的余晖里,他们看到了一幢接一幢的摩天高楼的轮廓在地平线上形成美丽的图案。以地平线为 X 轴,每幢高楼的轮廓是一个位于地平线上的矩形,彼此间可能有重叠的部分。奶牛一共看到了 N 幢高楼,第 i 幢楼的高度是 Hi,两条边界轮廓在地平线上的坐标是Ai 到 Bi。请帮助奶牛们计算一下,所有摩天高楼的轮廓覆盖的总面积是多少。

输入:

第一行:单个整数 N。

第二行到第 N + 1 行:第 i + 1 行有三个整数 Ai,Bi 和 Hi

输出:

单个整数:表示摩天高楼轮廓所覆盖的总面积

样例输入:

4

2 5 1

9 10 4

6 8 2

4 6 3

样例输出:

16

数据规模:

    60%:N<=1000

100%: N<=40000,Ai,Bi,Hi<=1e9

线段树扫描线裸题,不讲了吧...

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define int long long
 6 using namespace std;
 7 inline int read(){
 8     char chr=getchar();    int f=1,ans=0;
 9     while(!isdigit(chr)) {if(chr=='-') f=-1;chr=getchar();}
10     while(isdigit(chr))  {ans=(ans<<3)+(ans<<1);ans+=chr-'0';chr=getchar();}
11     return ans*f;
12 }struct P{int a,h,y1,tag;bool operator <(const P x)const{return a<x.a;}}a[40005<<1];
13 int n,p[40005<<1],len,ans,s[40005<<4],lz[40005<<4],ll[40005<<3],rr[40005<<3],l[40005<<3],r[40005<<3];
14 #define ls (i<<1)
15 #define rs (i<<1|1)
16 #define mid (l[i]+r[i]>>1)
17 void Build(int i,int llll,int rrrr){
18     l[i]=llll,r[i]=rrrr;
19     ll[i]=p[llll];rr[i]=p[rrrr];
20     if(l[i]+1==r[i]) return;
21     Build(ls,l[i],mid);Build(rs,mid,r[i]);
22 }inline void Push_Down(int i){
23     if(lz[i]>0)    return s[i]=rr[i]-ll[i],void();
24     if (l[i]+1==r[i]) s[i]=0;
25     else s[i]=s[ls]+s[rs];
26 }void Update(int i,P x){
27     if(rr[i]==x.h&&ll[i]==x.y1){lz[i]+=x.tag,Push_Down(i);return;}
28     if(x.h<=rr[ls])         Update(ls,x);
29     else if(x.y1>=ll[rs])    Update(rs,x);
30     else{
31         P t=x;t.h=rr[ls];Update(ls,t);//left
32         t=x;t.y1=ll[rs];Update(rs,t); //right
33     }Push_Down(i);
34 }inline void kai(){freopen("horizon.in","r",stdin);freopen("horizon.out","w",stdout);}
35 signed main(){//kai();
36     n=read();
37     for(int i=1;i<=n;i++){
38         int x=read(),y=read(),h=read();
39         a[i*2-1].a=x;a[i*2-1].y1=0;a[i*2-1].h=h;a[i*2-1].tag=1;p[i*2-1]=0;
40         a[i*2].a=y;a[i*2].y1=0;a[i*2].h=h;a[i*2].tag=-1;p[i*2]=h;
41     }sort(p,p+n*2+1);sort(a+1,a+n*2+1);
42     Build(1,1,n*2);Update(1,a[1]);
43     for(int i=2;i<=n*2;i++)ans+=s[1]*(a[i].a-a[i-1].a),Update(1,a[i]);
44     cout<<ans;
45     return 0;
46 }

T2过桥

题目描述:

一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥。桥已经很旧了, 所以它不能承受太重的东西。任何时候队伍在桥上的人都不能超过一定的限制. 所以这只队伍过桥时只能分批过,当一组全部过去时,下一组才能接着过。队伍里每个人过桥都需要特定的时间,当一批队员过桥时时间应该算走得最慢的那一个,每个人也有特定的重量,我们想知道如何分批过桥能使总时间最少。

输入:

第一行两个数: 桥能承受的最大重量w和队员总数n。

接下来n 行每行两个数分别表示:该队员过桥所需时间t和该队员的重量c。

输出:

 输出一个整数,表示最少的过桥时间。

样例输入:

100 3

24 60

10 40

18 50

样例输出:

42

数据规模:

50%: n<=10

100%: 100<=w<=400,1<=n<=16,1<=t<=50,10<=c<=100

  n<=16显然是状压DP,每次枚举子集,枚举哪些一组加入那些人,然后统计答案就OK了

  考场上想到了,不过还用了另一种方法:模拟退火

    随机化一个序列,贪心依次一个个加入人,计算出对于当前顺序是的极优答案,然后套上退火模板,本来觉得没有认真调参有60分差不多,没想到A了...

  这里给出两种方法的代码

状压:

 1 //状压方法
 2 //状压方法
 3 //状压方法
 4 #include<iostream>
 5 #include<cstdio>
 6 #include<cstring>
 7 #define inf 2000000000
 8 #define ll long long 
 9 using namespace std;
10 ll read(){
11     ll x=0,f=1;char ch=getchar();
12     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
13     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
14     return x*f;
15 }
16 int bin[20],t[20],w[20],f[65536],tim[65535],sum[65536],W,n;
17 int main(){
18     freopen("bridge.in","r",stdin);
19     freopen("bridge.out","w",stdout);
20     memset(f,127/3,sizeof(f));
21     bin[0]=1;for(int i=1;i<20;i++)bin[i]=bin[i-1]<<1;
22     W=read();n=read();
23     for(int i=1;i<=n;i++)t[i]=read(),w[i]=read();
24     for(int i=1;i<bin[n];i++)
25         for(int j=1;j<=n;j++)
26             if(i&bin[j-1])
27                 tim[i]=max(tim[i],t[j]),sum[i]+=w[j];
28     f[0]=0;
29     for(int i=1;i<bin[n];i++)
30         for(int j=i;j;j=i&(j-1))
31             if(sum[j]<=W)f[i]=min(f[i],tim[j]+f[i^j]);
32     printf("%d",f[bin[n]-1]);
33     return 0;
34 }

 

模拟退火:

 1 //模拟退火(考场代码)
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<ctime>
 7 #include<cstdlib>
 8 #include<cmath>
 9 using namespace std;
10 inline int read(){
11     char chr=getchar();    int f=1,ans=0;
12     while(!isdigit(chr)) {if(chr=='-') f=-1;chr=getchar();}
13     while(isdigit(chr))  {ans=(ans<<3)+(ans<<1);ans+=chr-'0';chr=getchar();}
14     return ans*f;
15 }inline void kai(){freopen("bridge.in","r",stdin);freopen("bridge.out","w",stdout);}
16 int n,w,p[50],ans=0x3f3f3f3f;
17 const double t_min=1e-14,delta=0.998,T=1926;
18 struct P{int t,c;}a[50];
19 //状压... 
20 inline int random(int x){return rand()%x+1;}
21 inline int get_ans(){
22     int t=0,tt=0,ans=0;
23     for(int i=1;i<=n;i++){
24         if(i==n)
25             if(t+a[p[i]].c>w) ans+=tt+a[n].t;    else ans+=max(a[n].t,tt);
26         else if(t+a[p[i]].c>w)    ans+=tt,t=a[p[i]].c,tt=a[p[i]].t;
27         else        tt=max(tt,a[p[i]].t),t+=a[p[i]].c;
28     }return ans;
29 }inline void Solve(){
30     double t=T;
31     int qans=ans;
32     while(t>t_min){
33         int x1=random(n),x2=random(n);
34         swap(a[x1],a[x2]);
35         int tans=get_ans();
36         int DE=-tans+ans;
37         if(DE>0){qans=tans;}
38         else if(exp(DE/t)*RAND_MAX<rand())    swap(a[x1],a[x2]),qans=tans;
39         ans=min(ans,qans);
40         t*=delta;
41     }
42 }
43 
44 int main(){
45     kai();
46     srand(19260817);
47     w=read(),n=read();
48     for(int i=1;i<=n;i++)a[i].t=read(),a[i].c=read();
49     for(int i=1;i<=n;i++) p[i]=i;
50     ans=get_ans();
51     for(int i=1;i<=8;i++) Solve();
52     cout<<ans;
53     return 0;
54 }

 

 T3:走迷宫

题目描述:

老胡被困在了一个迷宫里。迷宫可以视为N个点M条边的有向图,其中老胡处于起点S,迷宫的终点设为T。可惜的是,老胡非常的脑小,他只会从一个点出发随机沿着一条从该点出发的有向边,到达另一个点。这样,老胡走的步数可能很长,也可能是无限,更可能到不了终点。若到不了终点,则步数视为无穷大。但你必须想方设法求出老胡所走步数的期望值。

输入:

1行四个整数,N,M,S,T

2至M+1行每行两个整数x, y,表示有一条从xy的边。

输出:

    一个浮点数,保留小数点3位,为步数的期望值。若期望值为无穷大,则输出"INF"。

样例输入1:

6 6 1 6

1 2

1 3

2 4

3 5

4 6

5 6

样例输出1:

3.000

样例输入2

9 12 1 9

1 2

2 3

3 1

3 4

3 7

4 5

5 6

6 4

6 7

7 8

8 9

9 7

样例输出2

9.5000

样例输入3

2 0 1 2

样例输出3

INF

数据规模:

30%: N<=10,M<=100

60%: N<=200,M<=10000

另有40%:没有环与自环。

100%: N<=10000,M<=1e6,保证强连通分量的大小不超过100。

 考场上觉得是TARJAN+拓扑+DP,但是卡在了一个强连通分量内的算法,然后就一直在想,然后就来不及了...打了一个“INF”,没想到有20分...

其实强联通分量内高斯消元即可

高斯消元时,列方程f[i]=f[j]/d[i]+1f[i]=∑f[j]/d[i]+1,发现i的某些出边可能指向强连通分量外的点,把它们都当成常数项就好了。特别地,T的方程要特殊处理。

对于INF,只要S不可以到达T即是INF。

先贴上大佬(又是一道zz题*2)的代码

  1 #include<stack>
  2 #include<vector>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<iostream>
  6 #include<algorithm>
  7 using namespace std;
  8 const int MaxS=100+10,MaxN=10000+10,MaxM=1000000+10;
  9 stack<int> S;
 10 vector<int> scc[MaxN];
 11 struct Edge{int to,next;} e[MaxM];
 12 int n,m,cnt,scc_cnt,clk,s,t,u,v,first[MaxN],out_d[MaxN],pre[MaxN],low[MaxN],sccno[MaxN],id[MaxN],vis[MaxN];
 13 double f[MaxN],A[MaxS][MaxS];
 14 inline int getc() {
 15     static const int L = 1 << 15;
 16     static char buf[L], *S = buf, *T = buf;
 17     if (S == T) {
 18         T = (S = buf) + fread(buf, 1, L, stdin);
 19         if (S == T)
 20             return EOF;
 21     }
 22     return *S++;
 23 }
 24 inline int Read() {
 25     int c;
 26     while(!isdigit(c = getc()));
 27     int tmp = c - '0';
 28     while(isdigit(c = getc()))
 29         tmp = (tmp << 1) + (tmp << 3) + c - '0';
 30     return tmp;
 31 }
 32 inline int min(int a,int b) {return a<b?a:b;}
 33 inline void swap(int& a,int& b) {int tmp=a; a=b; b=tmp;}
 34 inline double abs(double x) {return x>0?x:-x;}
 35 inline void Add(int u,int v) {e[++cnt].to=v; e[cnt].next=first[u]; first[u]=cnt; out_d[u]++;}
 36 void dfs(int u)
 37 {
 38     pre[u]=low[u]=++clk; S.push(u);
 39     for (int i=first[u];i;i=e[i].next)
 40     {
 41         int v=e[i].to;
 42         if (!pre[v]) dfs(v),low[u]=min(low[u],low[v]); else if (!sccno[v]) low[u]=min(low[u],low[v]); 
 43     }
 44     if (low[u]==pre[u])
 45     {
 46         ++scc_cnt;
 47         while (S.top()!=u) 
 48         {
 49             sccno[S.top()]=scc_cnt;
 50             id[S.top()]=scc[scc_cnt].size();
 51             scc[scc_cnt].push_back(S.top());
 52             S.pop();
 53         }
 54         sccno[u]=scc_cnt; id[u]=scc[scc_cnt].size(); scc[scc_cnt].push_back(u); S.pop();;
 55     }
 56 }
 57 void travel(int u)
 58 {
 59     int v; 
 60     vis[u]=0; 
 61     if (u==sccno[t]) {vis[u]=1; return;}
 62     for (int i=0;i<scc[u].size();++i)
 63       for (int j=first[scc[u][i]];j;j=e[j].next) if ((v=sccno[e[j].to])!=u)
 64       {
 65           if (vis[v]==-1) travel(v);
 66           if (vis[v]==1) vis[u]=1;
 67       }
 68 }
 69 void Gauss(int n)
 70 {
 71     for (int i=0;i<n;++i)
 72     {
 73         int r=i;
 74         for (int j=i+1;j<n;++j) if (abs(A[j][i])>abs(A[r][i])) r=j;
 75         if (r!=i) for (int j=0;j<=n;++j) swap(A[r][j],A[i][j]);
 76         if (abs(A[i][i])<1e-6) continue;
 77         for (int j=i+1;j<n;++j)
 78         {
 79             double tmp=A[j][i]/A[i][i];
 80             for (int k=i+1;k<=n;++k) A[j][k]-=tmp*A[i][k];
 81         }
 82     }
 83     for (int i=n-1;i>=0;--i)
 84     {
 85         for (int j=i+1;j<n;++j) A[i][n]-=A[j][n]*A[i][j];
 86         A[i][n]/=A[i][i];
 87     }
 88 }
 89 void Calc(int u)
 90 {
 91     int v,size=scc[u].size();
 92     for (int i=0;i<size;++i)
 93       for (int j=first[scc[u][i]];j;j=e[j].next) 
 94       {
 95           v=sccno[e[j].to];
 96           if (v!=u&&!vis[v]) Calc(v);
 97       }
 98     memset(A,0,sizeof(A));
 99     for (int i=0;i<size;++i)
100     {
101         int k=scc[u][i];
102         A[i][i]=1; if (k==t) continue; 
103         A[i][size]=1;
104         for (int j=first[k];j;j=e[j].next) 
105         {
106             v=e[j].to;
107             if (sccno[v]==u) A[i][id[v]]-=1/(double)out_d[k];
108                else A[i][size]+=f[v]/out_d[k];
109         }
110     }
111     Gauss(size);
112     for (int i=0;i<size;++i) f[scc[u][i]]=A[i][size];
113     vis[u]=1;
114 }
115 int main()
116 {
117     freopen("maze.in","r",stdin);
118     freopen("maze.out","w",stdout);
119     n=Read(); m=Read(); s=Read(); t=Read();
120     if (s==t) {puts("0.000"); return 0;}
121     for (int i=1;i<=m;++i) {u=Read(); v=Read(); Add(u,v);}
122     for (int i=1;i<=n;++i) if (!pre[i]) dfs(i);
123     memset(vis,-1,sizeof(vis));
124     travel(sccno[s]);
125     for (int i=1;i<=scc_cnt;++i) if (vis[i]==0) {puts("INF"); return 0;}
126     memset(vis,0,sizeof(vis));
127     Calc(sccno[s]);
128     printf("%.3lf",f[s]);
129     return 0;
130 }

 

 

 

 

posted @ 2019-02-15 14:51  zheng_liwen  阅读(236)  评论(0编辑  收藏  举报
/*去广告*/