[NOIP 2013提高组][Wikioi]解题报告---龟速更新中

来源:互联网 发布:js面向对象的概念 编辑:程序博客网 时间:2024/05/17 23:09

Day1 T1 裸快速幂水题

//结果=(x+m*10^k)mod n#include <stdio.h>#define LL long long intLL n,m,k,x;LL fastPow(LL base,LL e) //base^e快速幂{LL out;if(e==0) return 1;out=fastPow(10,e/2);out*=out;out%=n;if(e%2==1) {out*=base; out%=n;}return out;}int main(){LL i,j;scanf("%lld%lld%lld%lld",&n,&m,&k,&x);printf("%lld\n",(x+(m*fastPow(10,k))%n)%n);return 0;}


 

Day1 T2 贪心+逆序对,我用n次二分,也就是nlogn的算法,交了题发现只有60分有木有!

/*题目思路:二分查找+线段树求逆序对*/#include <stdio.h>#include <stdlib.h>#define MAXN 300000#define MOD 99999997struct node{int num,v;}a[MAXN],b[MAXN];int c[MAXN],sum=0,n,tot[MAXN]; //sum=逆序对个数,aa是排序后的a数组,bb是排序后的b数组,c[i]=x表示a[i]移动到b数组中的x位置,tot[i]=结点i中int pos,ql,qr; //pos=比对的基准位置,eg:tot[i]=结点i上,在c[pos]后面,且比c[pos]小的数的个数int cmp(const void *x,const void *y){struct node *xx=(node *)x;struct node *yy=(node *)y;return (((xx->v)<(yy->v))?1:-1);}void build(int o,int L,int R) //建立结点编号{if(L==R) {if(L>pos&&c[L]<c[pos])tot[o]=1; else tot[o]=0;return;}int M=L+(R-L)/2;build(o*2,L,M);build(o*2+1,M+1,R);tot[o]=tot[o*2]+tot[o*2+1];tot[o]%=MOD;}int main(){int i,j;scanf("%d",&n);a[0].v=-1000;for(i=1;i<=n;i++) {scanf("%d",&a[i].v);a[i].num=i;}qsort(a,n+1,sizeof(a[0]),cmp);b[0].v=-1000;for(i=1;i<=n;i++){scanf("%d",&b[i].v);b[i].num=i;}qsort(b,n+1,sizeof(b[0]),cmp);for(i=1;i<=n;i++) c[b[i].num]=a[i].num; //排序后,记录下b数组中的Bx在a数组中对应的映射Ax//n次建立线段树求逆序对T_T,复杂度nlognfor(i=1;i<=n;i++){pos=i;build(1,1,n); //线段树初始化sum+=tot[1];sum%=MOD;}printf("%d\n",sum);return 0;}

后来发现虽然线段树和树状数组都是O(nlogn)的,但是树状数组常数小,于是写了树状数组版本的,AC

/*题目思路:树状数组+归并排序求逆序对*/#include <stdio.h>#include <stdlib.h>#include <algorithm>#define MAXN 300000#define MOD 99999997using namespace std;struct node{    int num,h; //编号 高度}a[MAXN],b[MAXN];bool cmp(node a,node b){return a.h<b.h;}int c[MAXN],tmp[MAXN],ans,n; //ans=逆序对个数int line[MAXN];int lowbit(int x){return x&(-x);}void update(int o,int v) //对位置为o更新,增加v{while(o<=n){line[o]+=v;o+=lowbit(o);}}int query(int o) //求1~o的和{int sum=0;while(o>0){sum+=line[o];o-=lowbit(o);}return sum;}int main(){    scanf("%d",&n);    a[0].h=-1000;    b[0].h=-1000;    for(int i=1;i<=n;i++)    {        scanf("%d",&a[i].h);        a[i].num=i;    }    for(int i=1;i<=n;i++)    {        scanf("%d",&b[i].h);        b[i].num=i;    }    sort(a+1,a+n+1,cmp); //排序    sort(b+1,b+n+1,cmp);    for(int i=1;i<=n;i++) c[a[i].num]=b[i].num; //记录下Ax的映射Bx,即排序后,a数组中第i个元素对应b数组中第i个元素,记录下a数组中每个编号的元素的b数组中对应元素编号     //要求出最少移动次数,求c数组的逆序对即可,简化过程,一个数组不动,只动另一个数组,逆序对的个数含义就是使c数组变成非递降序列的最少次数    for(int i=1;i<=n;i++){update(c[i],1);ans+=i-query(c[i]);ans%=MOD;}printf("%d\n",ans%MOD);    return 0;}


Day2 T1 模拟水题,文艺青年:贪心 普通青年:线段树 2B青年:打表

 

0 0
原创粉丝点击