2015暑期多校训练第一场 1,2,3

来源:互联网 发布:docker安装windows 10 编辑:程序博客网 时间:2024/05/16 09:52
//2015暑期多校训练第一场 1,2,3////本来想一天能够复习一套的,结果实在太艰难,一题差不多都能搞一天呢//而且内心的激动也是想在此时分享分享,前两道大神说的水题,我都理解//了大半天,第三题更是理解了三四天才懂了那么一丁点.继续加油吧,明天//继续搞!//hdu 5288 OO’s Sequence////对于一个a[i]记录左边一个L右边一个R,分别//代表最接近a[i]并且能够被a[i]整除的位置//每个a[i]的贡献值是(R[i] - i) * (i - L[i])//用一个pre值,记录每个数出现的位置.#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <vector>using namespace std;typedef long long ll;const int maxn = 100008;const ll MOD = 1e9 + 7; int a[maxn];int L[maxn];int R[maxn];int n;vector<int> p[10008];int pre[maxn];void init(){for (int i=1;i<=10000;i++){p[i].clear();for (int j=1;j*j<=i;j++){if (i%j==0){p[i].push_back(j);if (j*j!=i)p[i].push_back(i/j);}}}}void input(){for (int i=1;i<=n;i++){scanf("%d",&a[i]);}}void solve(){memset(pre,0,sizeof(pre));for (int i=1;i<=n;i++){int u = a[i];int ind = 0;for (int j=0;j<p[u].size();j++){ind = max(ind,pre[p[u][j]]);}L[i] = ind;pre[u] = i;}memset(pre,0x7f,sizeof(pre));for (int i=n;i>=1;i--){int u = a[i];int ind = n + 1;for (int j=0;j<p[u].size();j++){ind = min(ind,pre[p[u][j]]);}R[i] = ind;pre[u] = i;}ll ans = 0;for (int i=1;i<=n;i++){ans = (ans + (ll)(i-L[i]) * (R[i] - i))%MOD;}printf("%I64d\n",ans);}int main(){init();freopen("1.txt","r",stdin);while(scanf("%d",&n)!=EOF){input();solve();}}//hdu 5289 Assignment 单调队列////题目大意:////题目的意思就是让你求满足最大值最小值之差小与k的区间个数////解题思路:////单调队列,众所周知,单调队列能够维护滑动窗口的最大值和最小值//的问题.这里两者都有,我们都维护即可.我们用两个指针.一个指针表示//当前插入的元素,另一个指针表示满足条件的开始的元素的位置.维护单//调队列的时候我们插入一个元素,当发现插入该元素时,不满足题目所要//求的条件,并且第一个指针指向的位置出队.这时两个指针之间的距离就//是我们所能得到的区间的数目,累加结果就好.最后还要记得当所有的元//素都入队时,此时要看看j是否是最后的位置,因为此时还有满足条件的//区间.////感悟:////这道题多校训练的时候,是MY做出来的,用的就是单调队列,当时并不//怎么明白,后来也自己做了一遍,能想到维护最大值和最小值,但是这之间//的距离就不太清楚了.看了看题解,发现确实很奇妙.然后自己仔细仔细的//体会了一番,确实很不错.感谢这位神牛.也有的大神用的线段树做出来的//也有的是RMQ+二分.有多种解法.多开阔开阔思路,总是好的.继续加油哟~~~#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int maxn = 1e5 + 8;int n,k;int a[maxn];int deqmax[maxn];int deqmin[maxn];void input(){scanf("%d%d",&n,&k);for (int i = 1; i <= n; i++){scanf("%d",&a[i]);}}void solve(){int headmax,tailmax,headmin,tailmin;headmax = tailmax = headmin = tailmin = 0;long long ans = 0;int j = 1;for (int i=1;i <= n; i++){while(headmax < tailmax && a[deqmax[tailmax-1]] <= a[i])tailmax--;deqmax[tailmax++] = i;while(headmin < tailmin && a[deqmin[tailmin-1]] >= a[i])tailmin--;deqmin[tailmin++] = i;while(headmin < tailmin && headmax < tailmax && a[deqmax[headmax]]-a[deqmin[headmin]] >= k){ans += i - j;if (j == deqmax[headmax])headmax++;if (j == deqmin[headmin])headmin++;j++;}}while(j <= n){ans += n + 1 - j;j++;}printf("%I64d\n",ans);}int main(){int t;//freopen("1.txt","r",stdin);scanf("%d",&t);while(t--){input();solve();}}//hdu 5290 Bombing plan////题目大意:////给你一颗树,树上每个节点有一个权值w,当炸毁一个节点//时,距离它为w以内的点都被炸毁.则问当所有点被炸毁时//最小需要炸毁几个点.////解题思路:////树形dp.我们设立两个数组F[I][J],G[I][J].前者表示//I及I子树中所有节点全被炸毁,并且沿父节点向上距离//为J的点也被炸毁.后者表示I及I的子树中部分节点被炸毁//并且未被炸毁的点离I最远为J.//转移方程为://不取i点//F[i][j] = F[v][j+1] + min(F[L][0...j+1],G[L][0...j-1]);//G[i][j] = g[v][j-1] + min(F[L][0....j],G[L][0...j-1]);//G[i][0] = sigma(f[v][0]);////取i点//F[i][w[i]] = 1 + min(F[L][0...w[u]+1],G[L][0...w[u]-1]);////如果不好理解的话,那么本人按照自己的理解说一下,首先是F[i][j].//先选一个满足条件的能达到i向上距离为j的则为F[v][j+1].此时其他//的节点,子节点子树全被炸毁的范围F[L][0...j+1],子节点子树未被//全部炸毁g[i][j-1].G[i][j]同样是首先选择一个离i未炸毁的G[v][j-1]//其他的还是两种选择,要么未炸毁距离小于等于j要么全被炸毁.////初始化的时候单个叶子节点g[i][0] = 0,f[i][w[i]] = 1;其他的无穷大//但是不宜太大,容易造成数据溢出////看到一位大神写的在这题中,将无根树转化为有根树的时候,将1作为根.//并将1本身的节点另起一个编号挂在1上.这样的做法我感觉十分奇妙.自己还是//不很理解.希望大牛们能够不吝惜的指点小子一二.小子不慎感激////感悟:////多校第一场的第三题,当时根本就不会做,题解也看不懂.现在经过了玩耍的开心//时间,是时候逼迫自己去理解了,要不然水平怎么能提高呢,继续加油吧#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#include <vector>#define cls(x,a) memset(x,(a),sizeof(x))#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;const int maxn = 1e5 + 8;const int inf = 0x01010101;vector<int> e[maxn];int a[maxn];int F[maxn][111];int G[maxn][111];int p[maxn][111];int q[maxn][111];int n;void input(){for (int i=1;i<=n;i++){e[i].clear();}for (int i = 1;i <= n;i++){scanf("%d",&a[i]);}e[1].push_back(n+1);for (int i=1;i < n;i++){int u,v;scanf("%d%d",&u,&v);e[u].push_back(v);e[v].push_back(u);}cls(F,inf);cls(G,inf);cls(p,inf);cls(q,inf);}void dfs(int u,int fa){for (int i=0;i<e[u].size();i++){int v = e[u][i];if (v == fa)continue;dfs(v,u);}if (e[u].size()==1){G[u][0] = 0;F[u][a[u]] = 1;return;}for (int i=0;i<e[u].size();i++){int v = e[u][i];if (v == fa)continue;p[v][0] = F[v][0];q[v][0] = G[v][0];for (int j=1;j<103;j++){p[v][j] = min(p[v][j-1],F[v][j]);q[v][j] = min(q[v][j-1],G[v][j]);}}for (int j=0;j<103;j++){for (int k=0;k<e[u].size();k++){int v = e[u][k];if (v == fa)continue;if (F[v][j+1] == inf)continue;int f = F[v][j+1];for (int i=0;i<e[u].size();i++){int t = e[u][i];if (i==k || t == fa)continue;if (j)f += min(p[t][j+1],q[t][j-1]);elsef += p[t][j+1];}F[u][j] = min(F[u][j],f);}}int g = 0;for (int i=0;i<e[u].size();i++){int v = e[u][i];if (v==fa)continue;g += F[v][0];}G[u][0] = min(G[u][0],g);for (int j=1;j<103;j++){for (int k=0;k<e[u].size();k++){int v = e[u][k];if (v == fa)continue;if (G[v][j-1] == inf)continue;g = G[v][j-1];for (int i=0;i<e[u].size();i++){int t = e[u][i];if (i==k || t == fa)continue;g += min(p[t][j],q[t][j-1]);}G[u][j] = min(G[u][j],g);}}int f = 1;for (int i=0;i<e[u].size();i++){int v = e[u][i];if (v == fa)continue;if (a[u]){f += min(p[v][a[u]+1],q[v][a[u]-1]);}else {f += p[v][a[u]+1];}}F[u][a[u]] = min(F[u][a[u]],f);}void solve(){dfs(1,0);int ans = inf;for (int j=0;j<103;j++){ans = min(ans,F[1][j]);}printf("%d\n",ans);}int main(){freopen("1.txt","r",stdin);while(scanf("%d",&n)!=EOF){input();solve();}}

0 0
原创粉丝点击