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

Day1 T1 裸快速幂水题

//结果=(x+m*10^k)mod n
#include <stdio.h>

#define LL long long int

LL 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 99999997

struct 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,复杂度nlogn
	for(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 99999997

using 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青年:打表

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值