【日记】7.9
这个星期以来第一次发总结,因为目前为止就今天的题可以用来总结……
第一题,
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
【题目描述】 有N块编号为1~N的特殊磁石相互吸附组成一条磁性链,只有它们紧挨着时才会传递吸力,他们之间的吸力很大,如果我们要从N块相连的磁石中取出一块,那么需要消耗N-1个单位的能量,空缺处不再有吸力传递,空出的位置也不会再被吸到一起。现在我们要取出Q块磁石,并且给出它们的编号,问最少要消耗多少单位的能量? 【输人格式】 第一行两个数N和Q,Q表示要取走的磁石数; 第二行Q个数,表示要取走哪些编号的磁石。 【输出格式】 仅一行,表示最少消耗的能量。 【输入样例】 20 3 3 6 14 【输出样例】 35 【数据规模】 Q≤N; 50%的数据l≤N≤100;1≤Q≤5。 100%的数据l≤N≤1000;1≤Q≤100。
很简单的区间动态规划,我还无聊的加上了四边形不等式优化,结果我的快排+不等式优化被pb大神的冒泡+裸转移完爆了3倍的速度、、估计是数据规模太小的原因吧,优化现实不出来
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 *Prob : linka 3 *Data : 2012-7-9 4 *Sol : dp+四边形不等式 5 */ 6 7 #include <cstring> 8 #include <cstdio> 9 #include <cmath> 10 #include <algorithm> 11 12 #define MaxN 1100 13 #define MaxQ 200 14 15 using namespace std; 16 17 int n,q; 18 int a[MaxN],s[MaxN]; 19 int f[MaxQ][MaxQ]; 20 int g[MaxQ][MaxQ]; 21 22 int main() 23 { 24 freopen("linka.in","r",stdin); 25 freopen("linka.out","w",stdout); 26 27 scanf("%d%d",&n,&q); 28 for (int i=1; i<=q; i++) 29 scanf("%d",&a[i]); 30 sort(a+1,a+1+q); 31 32 a[0] = 0; 33 for (int i=1; i<=q; i++) 34 s[i] = a[i] - a[i-1] -1; 35 s[q+1] = n-a[q]; 36 for (int i=1; i<=q+1; i++) 37 s[i] += s[i-1]; 38 39 memset(f,127,sizeof(f)); 40 for (int i=1; i<=q+1; i++) { 41 g[i][i] = i; 42 f[i][i] = 0; 43 } 44 for (int i=q+1; i>=1; i--) 45 for (int j=i+1; j<=q+1; j++) 46 for (int k=g[i][j-1]; k<=g[i+1][j]; k++) 47 { 48 int tmp = f[i][k]+f[k+1][j]+(s[j]-s[i-1])+(j-i-1); 49 if (tmp<f[i][j]) { 50 g[i][j] = k; 51 f[i][j] = tmp; 52 } 53 } 54 55 printf("%d",f[1][q+1]); 56 57 fclose(stdin); fclose(stdout); 58 return 0; 59 }
第二题,
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
【题目描述】 一个简单的数列问题: 给定一个长度为n的数列,求这样的三个元素ai,aj,ak的个数, 满足ai〈aj〉ak,且i〈j〈k。 【输入格式】 第1行是一个整数n(1<=n<=50000)。 接下来n行,每行一个元素ai(0<=ai<=32767)。 【输出格式】 一个数,满足ai〈aj〉ak(i〈j〈k)的个数。 【输入样例】 5 1 2 3 4 1 【输出样例】 6 【数据规模】 对于30%的输入数据有n<=200。 对于80%的输入数据有n<=10000。 对于100%的输入数据有n<=50000。
已经无力吐槽这个题的简单程度了,写个线段树、平衡树、树状数组或者归并排序求逆序对各种搞各种过…我用的线段树…
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /*Task : b 2 *Data : 2.19 3 *Sol : 线段树 4 *Auth : Zhou Hang 5 */ 6 7 #include <cstdio> 8 #include <iostream> 9 #include <cstring> 10 #include <algorithm> 11 12 using namespace std; 13 14 const int MaxNum=40000; 15 const int MaxN=51000; 16 const int oo=1000000000; 17 18 int a[4*MaxNum+100][2]; 19 int m,n,ans,i,x,y,ch; 20 int l[MaxN],r[MaxN],h[MaxN]; 21 22 void updata(int l,int r,int root) 23 { 24 if ((y<l)||(x>r)) return; 25 26 if ((x<=l)&&(y>=r)) 27 { 28 a[root][0]++; a[root][1]++; 29 return; 30 } 31 32 int mid=(l+r)/2; 33 //必须是临时变量,避免递归时改变 34 35 //left child 36 a[root*2][0]+=a[root][1]; 37 a[root*2][1]+=a[root][1]; 38 //right child 39 a[root*2+1][0]+=a[root][1]; 40 a[root*2+1][1]+=a[root][1]; 41 //itself 42 a[root][1]=0; 43 44 updata(l,mid,root*2); 45 updata(mid+1,r,root*2+1); 46 //change Sum 47 a[root][0]=a[root*2][0]+a[root*2+1][0]; 48 } 49 50 int find(int l,int r,int root) 51 { 52 if ((y<l)||(x>r)) return 0; 53 if ((x<=l)&&(y>=r)) return a[root][0]; 54 55 int mid=(l+r)/2; 56 //left child 57 a[root*2][0]+=a[root][1]; 58 a[root*2][1]+=a[root][1]; 59 //right child 60 a[root*2+1][0]+=a[root][1]; 61 a[root*2+1][1]+=a[root][1]; 62 //itself 63 a[root][1]=0; 64 65 int m1=find(l,mid,root*2); 66 int m2=find(mid+1,r,root*2+1); 67 68 return m1+m2; 69 } 70 71 int main() 72 { 73 74 freopen("queueb.in","r",stdin); 75 freopen("queueb.out","w",stdout); 76 77 scanf("%d",&n); 78 79 int maxh = -1; 80 for (int i=1; i<=n; i++) { 81 scanf("%d",&h[i]); 82 if (h[i]>maxh) maxh = h[i]; 83 } 84 85 for (int i=1; i<=n; i++) { 86 x = y = h[i]; 87 updata(0,maxh,1); 88 x = 0; y = h[i]-1; 89 l[i] = find(0,maxh,1); 90 } 91 memset(a,0,sizeof(a)); 92 for (int i=n; i>=1; i--) { 93 x = y = h[i]; 94 updata(0,maxh,1); 95 x = 0; y = h[i]-1; 96 r[i] = find(0,maxh,1); 97 } 98 99 long long ans = 0; 100 for (int i=1; i<=n; i++) 101 ans += (long long)l[i]*r[i]; 102 103 cout<<ans<<endl; 104 105 fclose(stdin); fclose(stdout); 106 107 }
第三题,
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
【题目描述】 某商品推销员到某小区推销产品,产品推销除了商品质量好之外,还需要客户能影响和带动身边信赖他的人也购买,如果A购买了产品,那么信赖A的B就有可能也购买,那么信赖B的C就也可能成为潜在客户,依据这种信赖关系,就可能构成一个庞大的潜在客户网。聪明的推销员经过细心调查整理了这个小区里N个人的信赖关系,并且用1~N给这N个人编号。另外,这N个人中有P个潜在客户可能会被推销员直接说服购买产品,细心的推销员还估算了说服每个人具体需要花费的时间,那么请你帮推销员计算一下他最少需要花费多长时间来建立起这N个人的潜在客户网?如果不能把这N个人全部纳入潜在客户网,输出不能被纳入网络的人的编号。注意,信赖关系不一定是相互的啊! 【输人格式】 输入文件第一行只有一个整数n(n<=3000)。 第二行是整数p。表示能被说服的人数,1≤p≤n。 接下来的p行,每行有两个整数,第一个数是一个能被说服的人的编号,第二个数表示他被说服需要花费的时间。这个数不超过20000个时间单位。 紧跟着一行只有一个整数r,1≤r≤8000。然后r行,每行两个正整数,表示数对(A, B),B信赖A。 【输出格式】 如果可以把N个人全部纳入潜在客户网,第一行输出YES,并在第二行输出所需要花费的最少说服时间。否则输出NO,并在第二行输出不能纳入网络的人编号中,编号最小的。 【输入样例】 Example1: 3 2 1 10 2 100 2 1 3 2 3 Example2: 4 2 1 100 4 200 2 1 2 3 4 【输出样例】 Example1: YES 110 Example2: NO 3 【数据规模】 对于30%的输入数据有n<=10。 对于100%的输入数据有n<=3000。
唯一没有AC的题目……超时了两组。
加入一个超级源,能直接说服的就向他连边,权值为时间,对于数对(A,B),连边,权值为0,然后就是有向图的最小生成树,也就是最小树形图,根本不会……然后百度了一下,现学现写的,估计是因为用的邻接矩阵,所以时间复杂度到了O(N^3),超时了一两组,如果变成邻接表应该好很多。但是我已经不想再改了……先仍在这里了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 *Prob : salenet 3 *Data : 2012-7-9 4 *Sol : 骗分 5 */ 6 7 #include <cstdio> 8 #include <cstring> 9 #include <cmath> 10 11 #define MaxN 3010 12 #define oo 200000000 13 14 using namespace std; 15 16 int in[MaxN]; 17 int n,count; 18 bool used[MaxN],d[MaxN][MaxN]; 19 int a[MaxN][MaxN],mindis[MaxN]; 20 21 //dfs判断存在性 22 void dfs(int x) 23 { 24 used[x] = true; count++; 25 for (int i=1; i<=n; i++) 26 if (d[x][i]&&!used[i]) dfs(i); 27 } 28 29 //寻找环,返回其中的一个点 30 int find_circle(int x) 31 { 32 bool v[MaxN]; 33 memset(v,0,sizeof(v)); 34 int t = in[x]; 35 v[x] = true; 36 while (t&&!v[in[t]]) 37 v[t] = true, t = in[t]; 38 return t; 39 } 40 41 int min_tree_pic() 42 { 43 int i,j,k,u,tt,t,ans = 0; 44 memset(used,false,sizeof(used)); 45 count = 0; dfs(0); 46 if (count<n+1) return -1; 47 memset(used,false,sizeof(used)); 48 //初始in数组 49 for (i=1,k=0,in[0]=-1; i<=n; i++) { 50 for (j=0,t=oo; j<=n; j++) 51 if (!used[j]&&d[j][i]&&t>a[j][i]) { 52 t = a[j][i]; k = j; 53 } 54 in[i] = k; mindis[i] = t; 55 } 56 while (true) { 57 for (i=1; i<=n; i++) 58 if (!used[i]&&(tt=find_circle(i))) { 59 i = tt; 60 u = in[i]; 61 ans += mindis[i]; 62 while (u-i) { 63 used[u] = true; 64 ans += mindis[u]; u = in[u]; 65 } 66 for (j=0; j<=n; j++) 67 if (!used[j]&&j-i) 68 a[j][i] -= mindis[i]; 69 for (j=0; j<=n; j++) 70 if (!used[j]&&j-i) { 71 for (u=in[i]; u-i; u=in[u]) { 72 if(d[u][j]&&(a[u][j]<a[i][j]||!d[i][j])) //更新dis[i][j] 73 a[i][j]=a[u][j],d[i][j]=true; 74 if(d[j][u]&&(a[j][u]-mindis[u]<a[j][i]||!d[j][i]))//更新dis[j][i] 75 a[j][i]=a[j][u]-mindis[u],d[j][i]=true; 76 } 77 } 78 break; 79 } 80 if (i>n) break; 81 for(i=1,in[0]=-1;i<=n;i++)if(!used[i]) //需要重新生成in 82 { 83 for(j=0,t=oo,k=0;j<=n;j++)if(!used[j]&&d[j][i]&&t>a[j][i]) 84 t=a[j][i],k=j; 85 in[i]=k;mindis[i]=t; 86 } 87 } 88 for(i=1;i<=n;i++)if(!used[i]) //加上最后不成环的结点的mindis值 89 ans+=mindis[i]; 90 return ans; 91 } 92 93 int main() 94 { 95 freopen("salenet.in","r",stdin); 96 freopen("salenet.out","w",stdout); 97 98 int p,r,x,y,z; 99 100 scanf("%d",&n); 101 102 memset(d,false,sizeof(d)); 103 memset(a,0,sizeof(a)); 104 scanf("%d",&p); 105 for (int i=1; i<=p; i++) { 106 scanf("%d%d",&y,&z); 107 a[0][y] = z; 108 d[0][y] = true; 109 } 110 scanf("%d",&r); 111 for (int i=1; i<=r; i++) { 112 scanf("%d%d",&x,&y); 113 a[x][y] = 0; d[x][y] = true; 114 } 115 for (int i=0; i<=n; i++) 116 d[i][i] = 0; 117 118 int ans = min_tree_pic(); 119 if (ans<0) { 120 printf("NO\n"); 121 for (int i=1; i<=n; i++) 122 if (!used[i]) { printf("%d\n",i); break;} 123 } 124 else printf("YES\n%d\n",ans); 125 126 fclose(stdin); fclose(stdout); 127 return 0; 128 }
难度不大,不过考点很全面、有dp,数据结构和图论。