noip2013

D1:

T1:快速幂

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cmath>
#define LL long long 
using namespace std;
LL n,m,k,x;
inline LL quickpow(LL a,LL b){//a^b %n
    LL ans=1ll;
    while(b){
        if(b&1)ans=ans*a%n;

        a=a*a%n;            
        b>>=1;
    }
    return ans;
}
int main(){
//freopen("circle.in","r",stdin);
//freopen("circle.out","w",stdout);
    
scanf("%lld%lld%lld%lld",&n,&m,&k,&x);

printf("%lld",(x%n+m*quickpow(10ll,k)%n)%n);
    
    return 0;
}

T2:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<map>
#define LL long long
using namespace std;
const int maxn=1e5+5;
const int P=99999997;
int n;
int a[maxn],b[maxn],to[maxn],ans;
map<int ,int >pa;
map<int ,int >pb;

int sum[maxn];
inline int lowbit(int x){return x&(-x);}
inline int query(int p){
    int ans=0;
    while(p){
        ans+=sum[p];
        p-=lowbit(p);
    }
    return ans;
}
inline void modify(int p){
    while(p<=n){
        sum[p]++;
        p+=lowbit(p);
    }
}
int main(){
    //freopen("match.in","r",stdin);
    //freopen("match.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        pa[a[i]]=i;
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&b[i]);
        pb[b[i]]=i;
    }
    sort(a+1,a+n+1);
    sort(b+1,b+n+1);
    /*
  这里用到了排序不等式,(a-b)^2==a^2+b^2-2ab, 找到一个排列 s.t. -2ab max 自然想到排序不等式
  正序和 <= 乱序和 <= 逆序和
  */
for(int i=1;i<=n;i++){ to[ pa[a[i]] ]=pb[b[i]]; } memset(sum,0,sizeof(sum)); ans=0; for(int i=n;i;i--){//由于是相邻的两个火柴交换,直接求逆序对 ans=(ans+query(to[i]-1))%P; modify(to[i]); } printf("%d\n",ans); return 0; }

T3:

这题挺不好想,但是从部分分出发

30` && 60` 有向图两点间最小边最大,二分答案,O(q *log( m)* m )

但是其中填边的步骤可以省略,O(q*m)--------->kruscal 第一个使得两点联通的 边就是答案

100` 我们发现 每个询问都会填边太麻烦,然后我们想,推出两个性质

1:

如果该边是答案,那么他一定在该图的最大生成树中(反证法)

2:

如果该边是答案,那么两点联通 当且仅当 该边被添加(反证法)

于是就得到了满分算法,最大生成树+LCA最小边

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cmath>
#define LL long long 
using namespace std;
const int maxn=1e4+5;
const int maxm=5e4+5;
struct Edge{
    int u;
    int v;
    int w;
    const bool operator<(const Edge &x)const{return w<x.w;}
    inline void read(){
        scanf("%d%d%d",&u,&v,&w);
    }
}e[maxm];
int n,m,q;

int father[maxn];
int find(int x){return father[x]==x ? x : father[x]=find(father[x]);}//dsu

int fst[maxn],nxt[maxm<<1],to[maxm<<1],w[maxm<<1],edge_count;
inline void add(int x,int y,int z){
    edge_count++;
    to[edge_count]=y;
    w[edge_count]=z;
    nxt[edge_count]=fst[x];
    fst[x]=edge_count;
}

inline void kruscal(){
    for(int i=1;i<=n;i++)father[i]=i;//dsu_init
    
    sort(e+1,e+m+1);
    
    for(int i=m;i;i--){//鏈€澶х敓鎴愭爲
        int fu=find(e[i].u);int fv=find(e[i].v);
        if(fu==fv)continue;
        father[fu]=fv;
        
        add(e[i].u,e[i].v,e[i].w);
        add(e[i].v,e[i].u,e[i].w);                        
    }
}
const int INF=0x3f3f3f3f;

int f[maxn][50],g[maxn][50],deep[maxn],tre[maxn],temp;
void dfs(int u,int fa){
    tre[u]=temp;

    deep[u]=deep[fa]+1;
    for(int i=1;i<30;i++){
        f[u][i]=f[ f[u][i-1] ][i-1];
        g[u][i]=min(g[ f[u][i-1] ][i-1],g[u][i-1]);
    }

    for(int i=fst[u];i;i=nxt[i]){
        int v=to[i];
        if(v==fa)continue;
        f[v][0]=u;
        g[v][0]=w[i];
        dfs(v,u);
    }
}
inline void LCA_init(){
    memset(g,0x3f,sizeof(g));
    for(int i=1;i<=n;i++)if(!deep[i]){
        temp++;        
        dfs(i,0);
    }
}

inline int LCA(int x,int y){
    int ans=INF;

    if(deep[x]<deep[y])swap(x,y);
    for(int i=29;i>=0;i--){
        if(deep[f[x][i]]>=deep[y]){
            ans=min(ans,g[x][i]);
            x=f[x][i];
        }            
    }
    if(x==y)return ans;
    for(int i=29;i>=0;i--){
        if(f[x][i]!=f[y][i]){
            ans=min(ans,min(g[x][i],g[y][i]));
            x=f[x][i];y=f[y][i];            
        }
    }
    ans=min(ans,min(g[x][0],g[y][0]));
    return ans;
}
int main(){
//freopen("truck.in","r",stdin);
//freopen("truck.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        e[i].read();
    }
    kruscal();
    LCA_init();
    
    scanf("%d",&q);    
    for(int i=1,x,y;i<=q;i++){
        scanf("%d%d",&x,&y);
        if(tre[x]!=tre[y])printf("-1\n");
        else printf("%d\n",LCA(x,y));
    }
    return 0;
}

 D2:

T1:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e5+5;
int n,h[maxn];
LL ans;
int main(){
   // freopen("block.in","r",stdin);
   // freopen("block.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&h[i]);
    ans=0ll;
    for(int i=1;i<=n+1;i++){
        if(h[i]<h[i-1]){
            ans+=1ll*(h[i-1]-h[i]);
        }
    }
    printf("%lld\n",ans);
    return 0;
}

T2:

O(nlogn)???

虽然不是正解但是写的很开心,O(n^2)Dp+segment tree 优化

每次x要找比x大的 将要下降的 Dp值的最大值 +1

同理

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
const int maxh=1e6+5;
/*
main thought:
segment tree,维护两个,存储一下
以num结尾的将要上升的所有Dp值
以num结尾的将要下降的所有Dp值

每次x
从第一棵树里面找所有比他 小 的值中最大的Dp值
插入第二棵数中
从第二棵树里面找所有比他 大 的值中最大的Dp值
插入第一棵树中

*/
struct Node{
    int l;
    int r;
    int len;
    Node(int L=0,int R=0,int Len=0):l(L),r(R),len(Len){}    
    inline void update(const Node&a,const Node&b){
        len=max(a.len,b.len);
    }
    inline void modify(int x){
        len=max(len,x);
    }
}L[maxh<<2][2];
//0->将要上升,1->将要下降
void build(int k,int l,int r,bool b){
    L[k][b]=Node(l,r,0);
    
    if(l==r)return;
    else{
        int mid=(l+r)>>1;
        build(k<<1,l,mid,b);
        build(k<<1|1,mid+1,r,b);    
        return;
    }
}
void modify(int k,int p,int x,bool b){
    if(L[k][b].l==L[k][b].r) return L[k][b].modify(x);
    else{
        int mid=(L[k][b].l+L[k][b].r)>>1;
        if(p<=mid)modify(k<<1,p,x,b);
        else modify(k<<1|1,p,x,b);
        return L[k][b].update(L[k<<1][b],L[k<<1|1][b]);
    }
}
int query(int k,int l,int r,bool b){//max query
    if(l<=L[k][b].l&&L[k][b].r<=r)return L[k][b].len;
    else{
        int mid=(L[k][b].l+L[k][b].r)>>1;
        int ans=0;
        if(l<=mid)ans=max(ans,query(k<<1,l,r,b));
        if(mid<r)ans=max(ans,query(k<<1|1,l,r,b));
        return ans;
    }
}
int n,h[maxn];
//0->将要上升,1->将要下降
int main(){
    //freopen("flower.in","r",stdin);
    //freopen("flower.out","w",stdout);
    
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&h[i]);
    build(1,0,1000000,1);
    build(1,0,1000000,0);
    for(int i=1;i<=n;i++){
        if(h[i]<1000000)modify(1,h[i],query(1,h[i]+1,1000000,1)+1,0);//将要下降的max +1 加到 将要上升 中
        if(h[i]>0)modify(1,h[i],query(1,0,h[i]-1,0)+1,1);//将要上升的max +1 加到 将要下降 中
    }
printf(
"%d\n",max( query(1,0,1000000,1) , query(1,0,1000000,0) ) ); return 0; }

注意:!!!线段树进行修改查询的时候,要注意边界!!!

神奇做法:O(n)!!!

据说是找到拐点然后+2

std:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 1000000 + 10 ;
int vis,ans,n,h[maxn];
int main()
{
    //freopen("flower.in","r",stdin);    
    //freopen("flower.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;i++) scanf("%d",&h[i]);
    if(h[2]>=h[1]) vis=1;
    for(int i=2;i<=n;i++)
    {
        if(i==n && !vis) {ans++;break;}
        if(vis) if(h[i]>h[i+1]) {ans++;vis=0;continue;}
        if(!vis) if(h[i]<h[i+1]){ans++;vis=1;continue;}
    }
    cout<<ans+1<<endl;
    return 0;
}

 T3:

个人感觉写了双向广搜,理论上能将复杂度降低到  开一个根号

但是 忘记了 无解的情况都会跑满,所以比 单项广搜还慢一会

60`:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cstdlib>
#include<algorithm>
using namespace std;
/*
thought:
广搜判最短时间:
时间上:

空间上:每种状态只和空白块位置和目标快位置有关
共30^4种状态。。。

but
30^4*500=5e8

双向广搜!!!
也行,但是终止状态是4种,目标块在目标位置,空白块在4周
*/

int n,m,Q;
bool stable[50][50];
struct Node{
    int x,y;
    Node(int X=0,int Y=0):x(X),y(Y){}

    const bool operator==(const Node&a)const{
        return x==a.x&&y==a.y;
    }
    inline bool limit(){//判断是否合法
        return 0<x && x<=n && 0<y && y<=m && stable[x][y];
    }
    inline void read(){scanf("%d%d",&x,&y);}
    inline void write(){printf("%d %d\n",x,y);}
}e,s,t;
//0->正向,1->反向
struct Queue{//每种状态
    Node S,W;
    Queue(Node SS=Node(0,0),Node WW=Node(0,0)):S(SS),W(WW){}
    inline void write(){printf("~~~~~~~~~\n");S.write();W.write();printf("~~~~~~\n");}
}q[32*32*32*32][2];
int vis[32][32][32][32][2];//时间戳 判是否到达过
int step[32][32][32][32][2];//每种状态的步骤数
int front[2],rear[2];

const int dx[4]={0,1,0,-1};
const int dy[4]={1,0,-1,0};
inline void bfs(int i){
//printf("------------%d\n",i);
    front[0]=front[1]=rear[0]=rear[1]=0;
    
    q[rear[0]++][0]=Queue(s,e);
    step[s.x][s.y][e.x][e.y][0]=0;
    vis[s.x][s.y][e.x][e.y][0]=i;
    //q[front[0]][0].write();
    
    
    for(int j=0;j<4;j++){
        Node a=Node(t.x+dx[j],t.y+dy[j]);
        //printf("\na::");a.write();
        if(a.limit()){
            q[rear[1]++][1]=Queue(t,a);
            step[t.x][t.y][a.x][a.y][1]=0;
            vis[t.x][t.y][a.x][a.y][1]=i;
        }
    }
    //printf("???%d %d ???",front[1],rear[1]);
    //for(int j=front[1];j<rear[1];j++)q[j][1].write();
    //printf("begin to search:::");
    
    while(front[0]<rear[0] && front[1]<rear[1]){
        if(rear[0]-front[0]<rear[1]-front[1]){
            Queue &bg=q[front[0]][0];
//printf("bg:");bg.write();

            if(vis[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][1]==i){
                printf("%d\n",step[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][0]+step[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][1]);
                return;
            }
            
for(int j=0;j<4;j++){
    Node a=Node(bg.W.x+dx[j],bg.W.y+dy[j]);
    if(a.limit()){
    //a.write();
        if(a==bg.S){
            q[rear[0]][0]=Queue(bg.W,bg.S);
        }
        else{
            q[rear[0]][0]=Queue(bg.S,a);
        }
        Queue &ed=q[rear[0]][0];

        if(vis[ed.S.x][ed.S.y][ed.W.x][ed.W.y][0]!=i){
            
            step[ed.S.x][ed.S.y][ed.W.x][ed.W.y][0]=step[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][0]+1;
            vis[ed.S.x][ed.S.y][ed.W.x][ed.W.y][0]=i;
            rear[0]++;
        }
    }
}
            front[0]++;            
        }
        else{
            Queue &bg=q[front[1]][1];
//printf("bg:");bg.write();
            if(vis[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][0]==i){
                printf("%d\n",step[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][0]+step[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][1]);
                return;
            }
for(int j=0;j<4;j++){
    Node a=Node(bg.W.x+dx[j],bg.W.y+dy[j]);
    if(a.limit()){
    //a.write();
    
        if(a==bg.S){
            q[rear[1]][1]=Queue(bg.W,bg.S);
        }
        else{
            q[rear[1]][1]=Queue(bg.S,a);
        }
        Queue &ed=q[rear[1]][1];

        if(vis[ed.S.x][ed.S.y][ed.W.x][ed.W.y][1]!=i){
            
            step[ed.S.x][ed.S.y][ed.W.x][ed.W.y][1]=step[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][1]+1;
            vis[ed.S.x][ed.S.y][ed.W.x][ed.W.y][1]=i;
            rear[1]++;
        }
    }
}
            front[1]++;
        }
    }
    printf("-1\n");
}
int main(){
    freopen("puzzle.in","r",stdin);
    freopen("puzzle.out","w",stdout);
    scanf("%d%d%d",&n,&m,&Q);
    //printf("%d %d %d\n",n,m,Q);
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
        int _x;scanf("%d",&_x);stable[i][j]=_x;
    }
    for(int i=1;i<=Q;i++){
        e.read();//e.write();
        s.read();//s.write();
        t.read();//t.write();
        bfs(i);

        //if(i<q)memset(vis,0,sizeof(vis));
    }
    return 0;
}

70`:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int maxm = 30 + 5;
bool vis[maxm][maxm][maxm][maxm];
int map[maxm][maxm],n,m,q;
int exe,eye,sxs,sys,txt,tyt;
int dx[5]={0,0,0,1,-1},dy[5]={0,1,-1,0,0};
struct Node{int ex,ey,sx,sy,d;};
int bfs()
{
    queue<Node> pq;
    pq.push((Node){exe,eye,sxs,sys,0});
    vis[exe][eye][sxs][sys]=1;
    while(!pq.empty())
    {
        int ex=pq.front().ex,ey=pq.front().ey,sx=pq.front().sx,sy=pq.front().sy,d=pq.front().d;
        pq.pop();
        for(int i=1;i<=4;i++)
        {
            int nx=ex+dx[i],ny=ey+dy[i];
            if(nx<1 || nx>n || ny<1 || ny>m || !map[nx][ny]) continue; 
            if(nx==sx && ny==sy){
                if(vis[nx][ny][ex][ey]) continue;
                if(ex==txt && ey==tyt) return d+1;
                else{
                    pq.push((Node){nx,ny,ex,ey,d+1});vis[nx][ny][ex][ey]=1;
                }
            }
            else
            {
                if(vis[nx][ny][sx][sy]) continue;
                pq.push((Node){nx,ny,sx,sy,d+1});vis[nx][ny][sx][sy]=1;
            }
        }
    }
    return -1;
}
int main()
{
    freopen("puzzle.in","r",stdin);
    freopen("puzzle.out","w",stdout);
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&map[i][j]);
    for(int i=1;i<=q;i++)
    {
        memset(vis,0,sizeof(vis));
        scanf("%d%d%d%d%d%d",&exe,&eye,&sxs,&sys,&txt,&tyt);
        cout<<(sxs==txt&&sys==tyt?0:bfs())<<endl;
    }
    return 0;
}

std:没看懂

猜你喜欢

转载自www.cnblogs.com/a-blog-of-taojiayi-2003/p/11420347.html