2015 Multi-University Training Contest 1

来源:互联网 发布:mac删除dock图标 编辑:程序博客网 时间:2024/05/21 07:08

官方题解:http://blog.sina.com.cn/s/blog_15139f1a10102vnx5.html


1001

HDU 5288:http://acm.hdu.edu.cn/showproblem.php?pid=5288

题意:给出一个数组\(a[n]\),定义函数\(f(l,r)\)表示在区间\([l,r]\)内没有\(a_i\)的因子的\(i\)的数量,因子的下标不能为\(i\),求

$$\sum_{i=1}^{n}\sum_{j=i}^{n}f(i,j)\mod(10^9+1)$$


题目可以转换成每个\(a_i\)可以贡献的区间个数为\(K_i\),求出所有\(K_i\)之和

要求\(K_i\)就是找左右离\(a_i\)最近的2个因子,求出左右不包含因子的区间长度\(l,r\)

$$K_i=(l+1)\times (r+1)$$

$$ans=\sum_{i=1}^{n}K_i$$


要求出最近的因子可以预处理10000内所有数的因数,在输入的时候记录每个数出现的位置,因为记录是有序的,所以可以找出离\(a_i\)最近的两个因子


#include<cstdio>#include<algorithm>#include<iostream>#include<cmath>#include<cstring>#include<queue>using namespace std;#define MAX(a,b) ((a>b)?(a):(b))#define MIN(a,b) ((a<b)?(a):(b))#define LL __int64#define N 100005#define M 10005#define INF 1<<30#define MOD 1000000007int n;int a[N];vector<int> fac[M];vector<int> sit[M];void init(){    for(int i=1;i<M;++i){        for(int j=i;j<M;j+=i){            fac[j].push_back(i);        }    }}int main(){    init();while(scanf("%d",&n)!=EOF){        for(int i=1;i<=10000;i++)            sit[i].clear();        for(int i=1;i<=n;++i){            scanf("%d",&a[i]);            sit[a[i]].push_back(i);        }        LL ans=0;        LL ll,rr;        int flag;        for(int i=1;i<=n;++i){            ll=0,rr=n+1;            for(int j=0;j<fac[a[i]].size();++j){                flag=1;                for(int k=0;k<sit[fac[a[i]][j]].size();++k){                    if(sit[fac[a[i]][j]][k]<i){                        ll=MAX(ll,sit[fac[a[i]][j]][k]);                    }                    if(sit[fac[a[i]][j]][k]==i)continue;                    if(sit[fac[a[i]][j]][k]>i){                        rr=MIN(rr,sit[fac[a[i]][j]][k]);                        break;                    }                }            }            ll=i-ll-1;            rr=rr-i-1;            ans=(ans+(ll+1)*(rr+1))%MOD;        }        printf("%I64d\n",(ans)%MOD);}return 0;}


1002

HDU 5289:http://acm.hdu.edu.cn/showproblem.php?pid=5289


题意:求区间内的数两两之间差小于K的区间个数


RMQ+二分


先预处理出区间最大值和最小值

对于每个\(a_i\)可以用二分找出最大的r值满足区间[i,r]的最大值-最小值<K



#include<cstdio>#include<algorithm>#include<iostream>#include<cmath>#include<cstring>#include<queue>using namespace std;#define MAX(a,b) ((a>b)?(a):(b))#define MIN(a,b) ((a<b)?(a):(b))#define LL __int64#define INF 1<<30const int MAXN = 100010;int dp1[MAXN][20];int dp2[MAXN][20];int mm[MAXN];//初始化RMQ, b数组下标从1开始void initRMQ(int n,int b[]) {    mm[0] = -1;    for(int i = 1; i <= n; i++) {        mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];        dp1[i][0] = b[i];        dp2[i][0] = b[i];    }    for(int j = 1; j <= mm[n]; j++)        for(int i = 1; i + (1<<j) -1 <= n; i++){            dp1[i][j] = max(dp1[i][j-1],dp1[i+(1<<(j-1))][j-1]);            dp2[i][j] = min(dp2[i][j-1],dp2[i+(1<<(j-1))][j-1]);        }}//查询最大值int rmq1(int x,int y) {    int k = mm[y-x+1];    return max(dp1[x][k],dp1[y-(1<<k)+1][k]);}//查询最小值int rmq2(int x,int y) {    int k = mm[y-x+1];    return min(dp2[x][k],dp2[y-(1<<k)+1][k]);}int n,k;int a[MAXN];bool judge(int x,int y){    if(rmq1(x,y)-rmq2(x,y)<k)        return true;    return false;}int main() {    int T;    scanf("%d",&T);    int l,r,m;    LL ans;    while(T--){        scanf("%d%d",&n,&k);        ans=0;        for(int i=1;i<=n;++i)scanf("%d",&a[i]);        initRMQ(n,a);        for(int i=1;i<=n;++i){            l=i,r=n;            int e=i;            while(l<=r){                m=(l+r)>>1;                if(judge(i,m)){                    e=m;                    l=m+1;                }else{                    r=m-1;                }            }            ans+=(e-i+1);        }        printf("%I64d\n",ans);    }    return 0;}


1012

HDU 5299:http://acm.hdu.edu.cn/showproblem.php?pid=5299
题意:给出n个不想交的圆,两人轮流删圆,每次可以删去一个圆以及它包含的所有圆,不能删时为输

树上SG

如果做出圆的包含关系树,就是一个明显的树上SG。
对于树上SG附上一篇相关文章:树上删边游戏

这里直接说结论

树的删边游戏
从某一棵树上删除一条边,同时删去所有在删除边后不再与根相连的部分。双方轮流进行,无法再进行删除者判定为失败。

定理:
叶子节点的 SG 值为 0;

中间节点的 SG 值为它的所有子节点的 SG 值加 1 后的异或和。


对于建立圆的包含关系树,可以按半径从小到大排序,对于第一个大于并包含它的圆建边,然后break;

当然这是暴力的方法。交C++会TLE,交G++才会AC


#include<cstdio>#include<algorithm>#include<iostream>#include<cmath>#include<cstring>#include<queue>using namespace std;#define MAX(a,b) ((a>b)?(a):(b))#define MIN(a,b) ((a<b)?(a):(b))#define LL __int64#define N 100005#define INF 1<<30struct R{    int x,y,r;}o[N];bool cmp(R a,R b){    return a.r<b.r;}//判断包含关系,i被j包含int judge(int i,int j){    if((o[i].x-o[j].x)*(o[i].x-o[j].x)+(o[i].y-o[j].y)*(o[i].y-o[j].y)<(o[i].r-o[j].r)*(o[i].r-o[j].r))        return 1;    return 0;}struct node{    int to,next;}edge[N];int head[N],k;void init(){    k=1;    memset(head,0,sizeof(head));}void add(int u,int v){    edge[k].to=v;    edge[k].next=head[u];    head[u]=k++;}int dfs(int u){    int ret=0;    for(int i=head[u];i;i=edge[i].next){        ret^=(dfs(edge[i].to)+1);    }    return ret;}int main(){int T;int n;scanf("%d",&T);int ans,flag;while(T--){        init();        ans=0;        scanf("%d",&n);        for(int i=1;i<=n;++i){            scanf("%d%d%d",&o[i].x,&o[i].y,&o[i].r);        }        sort(o+1,o+n+1,cmp);        for(int i=1;i<=n-1;++i){            flag=0;            for(int j=i+1;j<=n;++j){                if(judge(i,j)){                    add(j,i);                    flag=1;                    break;                }            }            if(!flag){                add(0,i);            }        }        add(0,n);        ans=dfs(0);        if(ans)printf("Alice\n");        else   printf("Bob\n");}return 0;}





(待续。。。)



0 0
原创粉丝点击