周末训练笔记(10.8)—hdu3016+poj2886

来源:互联网 发布:windows c盘清理 编辑:程序博客网 时间:2024/05/20 10:10

国庆假期过得还真快啊,感觉还没干啥就又回来了,树状数组的题目刷的差不多了(题目不一一发了),扫扫尾就结束了,“沉迷”于线段树“无法自拔”,个人感觉线段树好用一些,线段树的耗费空间是大了些,但是以空间换时间还是很划算的,最重要的是适用范围广,各有各的优点吧。

——补上几道思维题。

Man Down

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 17   Accepted Submission(s) : 8
Problem Description
The Game “Man Down 100 floors” is an famous and interesting game.You can enjoy the game from 
http://hi.baidu.com/abcdxyzk/blog/item/16398781b4f2a5d1bd3e1eed.html

We take a simplified version of this game. We have only two kinds of planks. One kind of the planks contains food and the other one contains nails. And if the man falls on the plank which contains food his energy will increase but if he falls on the plank which contains nails his energy will decrease. The man can only fall down vertically .We assume that the energy he can increase is unlimited and no borders exist on the left and the right.

First the man has total energy 100 and stands on the topmost plank of all. Then he can choose to go left or right to fall down. If he falls down from the position (Xi,Yi),he will fall onto the nearest plank which satisfies (xl <= xi <= xr)(xl is the leftmost position of the plank and xr is the rightmost).If no planks satisfies that, the man will fall onto the floor and he finishes his mission. But if the man’s energy is below or equal to 0 , he will die and the game is Over.

Now give you the height and position of all planks. And ask you whether the man can falls onto the floor successfully. If he can, try to calculate the maximum energy he can own when he is on the floor.(Assuming that the floor is infinite and its height is 0,and all the planks are located at different height).
 

Input
There are multiple test cases. For each test case, The first line contains one integer N (2 <= N <= 100,000) representing the number of planks. Then following N lines representing N planks, each line contain 4 integers (h,xl,xr,value)(h > 0, 0 < xl < xr < 100,000, -1000 <= value <= 1000), h represents the plank’s height, xl is the leftmost position of the plank and xr is the rightmost position. Value represents the energy the man will increase by( if value > 0) or decrease by( if value < 0) when he falls onto this plank.
 

Output
If the man can falls onto the floor successfully just output the maximum energy he can own when he is on the floor. But if the man can not fall down onto the floor anyway ,just output “-1”(not including the quote)
 

Sample Input
410 5 10 105 3 6 -1004 7 11 202 2 1000 10
 

Sample Output
140
 
题意:n快木板,给出高度,左限,右限,val,每次只能竖直下落,地面无限,问你最大的val是多少,初始100

思路:这个题目的处理挺巧妙的,夹杂着dp,主要的一点就是以木板的长度建树,然后开始覆盖,上面的木板覆盖下面的木板。这样的目的在于快速的确定下一步可以走动的木板。

#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#define N 100010#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;int tree[N<<2];struct node{    int lx,rx,val;    int h;}map[100010];bool cmp(node a,node b){    return a.h<b.h;    }int lid[N],rid[N],dp[N];void build(int l,int r,int rt){    tree[rt]=0;    if(l==r)     return;    int m=(l+r)>>1;    build(lson);    build(rson);}int id;void update(int &L,int &R,int l,int r,int rt){    if(L<=l&&R>=r)    {        tree[rt]=id;        return;    }    if(tree[rt]!=-1)    {        tree[rt<<1]=tree[rt<<1|1]=tree[rt];        tree[rt]=-1;        }    int m=(l+r)>>1;    if(L<=m) update(L,R,lson);    if(R>m)  update(L,R,rson);}int query(int index,int l,int r,int rt){    if(tree[rt]!=-1)        return tree[rt];    int m=(l+r)>>1;    if(index<=m) return query(index,lson);    return query(index,rson);}int main(){    int n;    int i,k;    while(scanf("%d",&n)!=EOF)    {        memset(dp,0,sizeof(dp));        k=0;        for(i=1;i<=n;i++)        {            scanf("%d%d%d%d",&map[i].h,&map[i].lx,&map[i].rx,&map[i].val);            if(map[i].rx>k) k=map[i].rx;        }        sort(map+1,map+n+1,cmp);        build(1,k,1);        for(i=1;i<=n;i++)        {            lid[i]=query(map[i].lx,1,k,1);            rid[i]=query(map[i].rx,1,k,1);            id=i;            update(map[i].lx,map[i].rx,1,k,1);        }        dp[n]=100+map[n].val;        for(i=n;i>=1;i--)        if(dp[i]>0)        {            dp[lid[i]]=max(dp[lid[i]],dp[i]+map[lid[i]].val);            dp[rid[i]]=max(dp[rid[i]],dp[i]+map[rid[i]].val);        }        if(dp[0]>0)printf("%d\n",dp[0]);        else cout<<-1<<endl;    }    return 0;    }


Who Gets the Most Candies?

Time Limit : 10000/5000ms (Java/Other)   Memory Limit : 262144/131072K (Java/Other)
Total Submission(s) : 28   Accepted Submission(s) : 11
Problem Description

N children are sitting in a circle to play a game.

The children are numbered from 1 to N in clockwise order. Each of them has a card with a non-zero integer on it in his/her hand. The game starts from the K-th child, who tells all the others the integer on his card and jumps out of the circle. The integer on his card tells the next child to jump out. Let A denote the integer. If A is positive, the next child will be the A-th child to the left. If A is negative, the next child will be the (A)-th child to the right.

The game lasts until all children have jumped out of the circle. During the game, the p-th child jumping out will get F(p) candies where F(p) is the number of positive integers that perfectly divide p. Who gets the most candies?

 

Input
There are several test cases in the input. Each test case starts with two integers <i>N</i> (0 < <i>N</i> <span lang="en-us">≤ 500,000) and <i>K</i> (1 ≤ <i>K</i> ≤ <i>N</i>) on the first line. The next <i>N</i> lines contains the names of the children (consisting of at most 10 letters) and the integers (non-zero with magnitudes within 10<sup>8</sup>) on their cards in increasing order of the children’</span>s numbers, a name and an integer separated by a single space in a line with no leading or trailing spaces.
 

Output
<p>Output one line for each test case containing the name of the luckiest child and the number of candies he/she gets. If ties occur, always choose the child who jumps out of the circle first.</p>
 

Sample Input
4 2Tom 2Jack 4Mary -1Sam 1
 

Sample Output
Sam 3
题意:n个小朋友,围成圈坐下,每次站起来一个附带一个数字,正代表顺时针数,负则逆时针数,起来的人获得轮数的因数的总个数个糖果,问最后最多的是谁?
思路:反素数对于任何正整数x,其约数的个数记做g(x).例如g(1)=1,g(6)=4.如果某个正整数x满足:对于任意i(0<i<x),都有g(i)<g(x),则称x为反素数·
先稀里糊涂的看看反素数的定义,copy上范围内的反素数以及约数个数,这样求出最后出队的位置即可
#include<iostream>#include<string.h>#include<stdio.h>#define lson l,m ,rt<<1#define rson m+1,r,rt<<1|1#define maxn 500010using namespace std;char name[maxn][12];int num[maxn];int rprim[35][2]={    498960,200,332640,192,277200,180,221760,168,166320,160,    110880,144,83160,128,55440,120,50400,108,45360,100,    27720,96,25200,90,20160,84,15120,80,10080,72,    7560,64,5040,60,2520,48,1680,40,1260,36,    840,32,720,30,360,24,240,20,180,18,    120,16,60,12,48,10,36,9,24,8,    12,6,6,4,4,3,2,2,1,1        };int tree[maxn<<2];int n,k;void pushup(int rt){    tree[rt]=tree[rt<<1]+tree[rt<<1|1];}void bulid(int l,int r,int rt){    if(l==r){        tree[rt]=1;        return ;    }    int m=(l+r)/2;    bulid(lson);    bulid(rson);    pushup(rt);}void update(int p,int add,int l,int r,int rt){    if(l==r){        tree[rt]=add;        k=l;        return ;    }    int m=(l+r)>>1;    if(p<=tree[rt<<1])update(p,add,lson);    else update(p-tree[rt<<1],add,rson);    pushup(rt);}int query(int L,int R,int l,int r,int rt){    if(L<=l && r<=R){        return tree[rt];    }    int m=(l+r)>>1;    int ret=0;    if(L<=m)ret+=query(L,R,lson);    if(R>m)ret+=query(L,R,rson);    return ret;}int main(){    while(cin>>n>>k)    {        int p=0;        while(n<rprim[p][0])        p++;        int x=rprim[p][0];        bulid(1,n,1);        for(int i=1;i<=n;i++)            scanf("%s %d",name[i],&num[i]);        int m=n;        int now=k;        for(int i=1;i<x;i++)        {            update(now,0,1,n,1);            m--;            if(num[k]%m==0)            {                if(num[k]>0)num[k]=m;                else num[k]=1;            }            else{                num[k]%=m;                if(num[k]<0)                num[k]+=m+1;            }            int left=query(1,k,1,n,1);            int right=m-left;            if(num[k]<=right)            {                now=left+num[k];            }else{                now=num[k]-right;            }        }        update(now,0,1,n,1);        cout<<name[k]<<" "<<rprim[p][1]<<endl;    }    return 0;}




小明系列问题——小明序列

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 48   Accepted Submission(s) : 25
Problem Description
  大家都知道小明最喜欢研究跟序列有关的问题了,可是也就因为这样,小明几乎已经玩遍各种序列问题了。可怜的小明苦苦地在各大网站上寻找着新的序列问题,可是找来找去都是自己早已研究过的序列。小明想既然找不到,那就自己来发明一个新的序列问题吧!小明想啊想,终于想出了一个新的序列问题,他欣喜若狂,因为是自己想出来的,于是将其新序列问题命名为“小明序列”。

  提起小明序列,他给出的定义是这样的:
  ①首先定义S为一个有序序列,S={ A1 , A2 , A3 , ... , An },n为元素个数 ;
  ②然后定义Sub为S中取出的一个子序列,Sub={ Ai1 , Ai2 , Ai3 , ... , Aim },m为元素个数 ;
  ③其中Sub满足 Ai1 < Ai2 < Ai3 < ... < Aij-1 < Aij < Aij+1 < ... < Aim ;
  ④同时Sub满足对于任意相连的两个Aij-1与Aij都有 ij - ij-1 > d (1 < j <= m, d为给定的整数);
  ⑤显然满足这样的Sub子序列会有许许多多,而在取出的这些子序列Sub中,元素个数最多的称为“小明序列”(即m最大的一个Sub子序列)。
  例如:序列S={2,1,3,4} ,其中d=1;
  可得“小明序列”的m=2。即Sub={2,3}或者{2,4}或者{1,4}都是“小明序列”。

  当小明发明了“小明序列”那一刻,情绪非常激动,以至于头脑凌乱,于是他想请你来帮他算算在给定的S序列以及整数d的情况下,“小明序列”中的元素需要多少个呢?
 

Input
  输入数据多组,处理到文件结束;   输入的第一行为两个正整数 n 和 d;(1<=n<=10^5 , 0<=d<=10^5)   输入的第二行为n个整数A1 , A2 , A3 , ... , An,表示S序列的n个元素。(0<=Ai<=10^5)
 

Output
  请对每组数据输出“小明序列”中的元素需要多少个,每组测试数据输出一行。
 

Sample Input
2 01 25 13 4 5 1 25 23 4 5 1 2
 

Sample Output
221

#include<iostream>#include<stdio.h>#include<string.h>using namespace std;int a[100010],dp[100010],c[100010];int n,k;int bin(int t){    int l=1,r=n;    while(l<=r)    {        int mid=(l+r)/2;        if(t>c[mid])            l=mid+1;        else            r=mid-1;    }    return l;}int solve(){    int ans=0;    for(int i=1;i<=n;i++)    {        dp[i]=bin(a[i]);        if(dp[i]>ans)        ans=dp[i];        int j=i-k;        if(j>0&&c[dp[j]]>a[j])            c[dp[j]]=a[j];    }    return ans;}int main(){    while(cin>>n>>k)    {        memset(c,0x3f3f3f3f,sizeof(c));        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);        }        printf("%d\n",solve());    }    return 0;}