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