NOIP2013Day1

已完结

T1 转圈游戏

初看以为是啥神仙数学题。
直到我发现他是day1t1才确定这真的是快速幂。
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
inline ll _() {
	ll x=0,f=1; char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())
		if(ch=='-')f=-f;
	for(;ch>='0'&&ch<='9';ch=getchar())
		x=x*10+ch-'0';
	return x*f;
}
#define _ _()
ll n,m,k,x;
inline ll power(ll a,ll b) { 
    ll res=1;
    while(b) {
        if(b&1) res=res*a%n;
        b>>=1; a=a*a%n;
    }
    return res;
}
int main() {
    n=_; m=_; k=_; x=_;
    printf("%lld\n",(x+m*power(10,k)%n)%n);
}

T2 火柴排队

根据直觉,好像是俩个序列排个序就行了
能够保证那个表达式的值最小
为啥...假设我a对应b,c对应d... (a<=c;b<=d)
(a-b)^2+(c-d)^2 与 (a-d)^2+(b-c)^2谁大谁小呢
拆开
1.a^2 + b^2 - 2ab + c^2 + d^2 - 2cd
2.a^2 + d^2 - 2ad + b^2 + c^2 - 2bc
所以,谁大谁小完全取决于
2ab + 2cd 与2ad + 2bc谁大
2ab + 2cd - 2ad - 2bc=2(ab + cd - ad - bc)=2(a*(b-d)+c*(d-b))
∵b<=d a<=c
所以这个式子2ab + 2cd - 2ad - 2bc>0
所以可以证明...小的对应小的,大的对应大的是对的
也即a{}和b{}分别排序后下标相同的一一对应
如样例
4
2 3 1 4
3 2 1 4
第一个序列我看成...
1 2 3 4
那么第二个序列我就能表示成...
2 1 3 4
然后就是求个逆序对了
/**************************************************************
    User: ZincSabian
    Language: C++
****************************************************************/
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
inline ll _() {
	ll x=0,f=1; char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())
		if(ch=='-')f=-f;
	for(;ch>='0'&&ch<='9';ch=getchar())
		x=x*10+ch-'0';
	return x*f;
}
#define _ _()
int a[100005],b[100005],c[100005],pos[100005];
int n,N,ans;
int t[100005];
inline void add(int x) {
	for(;x<=n;x+=(x&-x)) t[x]++;
}
inline int query(int x) {
	int res=0;
	for(;x;x-=(x&-x)) res+=t[x];
	return res;
}
int main() { 
	n=_;
	for(int i=1;i<=n;i++) {
		b[i]=a[i]=_;
	}
	sort(b+1,b+n+1);
	N=unique(b+1,b+n+1)-b-1;
	for(int i=1;i<=n;i++) {
		a[i]=lower_bound(b+1,b+n+1,a[i])-b-1;
		pos[a[i]]=i;
	}
	for(int i=1;i<=n;i++) {
		b[i]=c[i]=_; 
	}
	sort(b+1,b+n+1);
	N=unique(b+1,b+n+1)-b-1;
	for(int i=1;i<=n;i++) {
		c[i]=lower_bound(b+1,b+n+1,c[i])-b-1;
		c[i]=pos[c[i]];
		add(c[i]);
		ans=(ans+i-query(c[i]))%99999997;
	}
	printf("%d\n",ans);
} 

T3 货车运输

跑出最大生成树,然后上Kruskal重构树|倍增。
当时写的是倍增
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
inline ll _() {
    ll x=0,f=1; char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())
        if(ch=='-')f=-f;
    for(;ch>='0'&&ch<='9';ch=getchar())
        x=x*10+ch-'0';
    return x*f;
}
#define _ _()
const int N=5e4+5;
int n,m; 
struct edge {
    int u,v,w;
    bool operator < (const edge b) const {
        return w>b.w;
    } 
}b[N];
struct Edge { int to,nxt,w; }e[N<<1];
int cnt,head[N];
inline void insert(int u,int v,int w) {
    e[cnt]=(Edge) {v,head[u],w};
    head[u]=cnt++;
}
inline void ins(int u,int v,int w) {
    insert(u,v,w); insert(v,u,w);
}
int pre[N],siz[N],dep[N],f[N][20],mn[N][20],ans;
inline int find(int x) { return pre[x]==x?x:pre[x]=find(pre[x]); }
inline void dfs(int x,int fa) {
    dep[x]=dep[fa]+1;
    for(int i=1;i<20;i++)
        f[x][i]=f[f[x][i-1]][i-1],mn[x][i]=min(mn[x][i-1],mn[f[x][i-1]][i-1]);
    for(int i=head[x];~i;i=e[i].nxt)
        if(e[i].to!=fa) {
            mn[e[i].to][0]=e[i].w; f[e[i].to][0]=x;
            dfs(e[i].to,x);
        }
}
inline int lca(int x,int y) {
    ans=2e9;
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=19;~i;i--) {
        if(dep[f[x][i]]>=dep[y]) {
            ans=min(ans,mn[x][i]);
            x=f[x][i];
        }
        if(x==y) return x;
    }
    for(int i=19;~i;i--)
        if(f[x][i]!=f[y][i])
            ans=min(ans,min(mn[x][i],mn[y][i])),x=f[x][i],y=f[y][i];
    ans=min(ans,min(mn[x][0],mn[y][0]));
    return f[x][0];
}
int main() {
    n=_; m=_;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++)
        for(int j=0;j<20;j++)
            mn[i][j]=2e9;
    for(int i=1;i<=n;i++)
        pre[i]=i,siz[i]=1;
    for(int i=1;i<=m;i++)
        b[i].u=_,b[i].v=_,b[i].w=_;
    sort(b+1,b+m+1);
    for(int i=1;i<=m;i++) {
        int x=find(b[i].u),y=find(b[i].v);
        if(x!=y) { 
            ins(b[i].u,b[i].v,b[i].w);
            if(siz[x]<siz[y]) swap(x,y);
            siz[x]+=siz[y];
            pre[y]=x;
        }
    }
    for(int i=1;i<=n;i++)
        if(pre[i]==i) dfs(i,0);
    int q=_;
    while(q--) {
        int x=_,y=_;
        if(find(x)!=find(y)) { puts("-1"); continue; }//lca(x,y);
        lca(x,y);
        printf("%d\n",ans);
    }
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值