http://acm.zcmu.edu.cn/JudgeOnline/contest.php?cid=1086

签到

直接累加学号,再去掉来的,剩下的就是没有来的,注意数据范围较大使用long long

也可以使用异或操作,或者STL map或者set

#include<iostream>
#include<cstdio>
using namespace std;
int n;
int main()
{
    while(~scanf("%d",&n))
    {
        int ans,x;
        scanf("%d",&ans);
        for(int i=0;i<2*(n-1);i++)scanf("%d",&x),ans^=x;
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

完美变换

数n每次有三种选择 n-1,n+2,n/3,n/3的下降到1的速度最快,用bfs 每次将可以用的选择加入队列,即可算出最小变换次数。bfs时,按照n/3 ,n-1 ,n-2的顺序放入队列。步数相同的层中,如果后面的数等于前面的数则舍弃后面的数。因为如果前面的数无解的话后面的数也无解;如果前面的数有解,那么后面的字典序会比前面的字典序大。

因为bfs过程中不可能有相同的数出现(否则舍弃第二次出现的相同数),所以直接用map记录前一个数就可以了

#include<iostream>
#include<cstdio>
#include<map>
#include<queue>
using namespace std;
queue<pair<int,int> >q;
map<int,int>pre;
map<int,bool>vis;
int n;
void output(int val)
{
    if(val==n){
        printf("%d",n);
        return;
    }
    output(pre[val]);
    printf("->%d",val);
}
void bfs()
{
    while(!q.empty())q.pop();
    q.push(make_pair(n,0));
    vis[n]=true;
    while(!q.empty())
    {
        int val=q.front().first;
        int step=q.front().second;
        int tmp;
        q.pop();
        if(val==1)
        {
            printf("%d ",step);
            output(val);
            puts("");
            return;
        }
        tmp=val/3;
        if(val%3==0&&vis[tmp]==false)
        {
            q.push(make_pair(tmp,step+1));
            pre[tmp]=val;
            vis[tmp]=true;
        }
        tmp=val-1;
        if(vis[tmp]==false)
        {
            q.push(make_pair(tmp,step+1));
            pre[tmp]=val;
            vis[tmp]=true;
        }
        tmp=val+2;
        if(vis[tmp]==false)
        {
            q.push(make_pair(tmp,step+1));
            pre[tmp]=val;
            vis[tmp]=true;
        }
    }
}
int  main()
{
    while(~scanf("%d",&n))
    {
        vis.clear();
        pre.clear();
        bfs();
    }
    return 0;
}
View Code

 

愉快的玩耍 FZU2150

暴力乱搞

题意是在图上选择两个点(可以重合)进行搜索,最小的步数烧完所有草。

先用dfs检验数据,相邻的草算作一块,如果大于两块,则无解。

如果有解,则bfs。 如果选的是同一个点,则将一个点加入队列,如果选的是不同的点,则将两个点加入队列。

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
struct ss
{
    int x,y;
    int step;
}t;
//l u r d
int dx[4]={0,-1,0,1};
int dy[4]={-1,0,1,0};
int n,m;
int cnt;
char mp[20][20];
bool vis[20][20];
vector<pair<int,int> >v;
queue<ss>q;
void dfs(int x,int y)
{
    vis[x][y]=true;
    for(int i=0;i<4;i++)
    {
        int xx=x+dx[i];
        int yy=y+dy[i];
        if(xx>=0&&xx<n&&yy>=0&&yy<m&&mp[xx][yy]=='#'&&!vis[xx][yy])
            dfs(xx,yy);
    }
}
int bfs()
{
    int num=0;
    while(!q.empty())
    {
        ss p=q.front();
        q.pop();
        num++;
        if(num==cnt)
        {
            return p.step;
        }
        for(int i=0;i<4;i++)
        {
            t.x=p.x+dx[i];
            t.y=p.y+dy[i];
            t.step=p.step+1;
            if(t.x>=0&&t.x<n&&t.y>=0&&t.y<m&&mp[t.x][t.y]=='#'&&!vis[t.x][t.y])
            {
                vis[t.x][t.y]=true;
                q.push(t);
            }
        }
    }
    return -1;

}
int main()
{
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++)
    {
        cnt=0;
        v.clear();
        while(!q.empty())q.pop();
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++){
            scanf("%s",mp[i]);
            for(int j=0;j<m;j++)
            {
                if(mp[i][j]=='#'){
                    v.push_back(make_pair(i,j));
                }
            }
        }
        ///dfs检验数据,只要块大于2就无解
        memset(vis,false,sizeof(vis));
        int  block=0;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(mp[i][j]=='#'&&!vis[i][j])
                {
                    dfs(i,j);
                    block++;
                }
            }
        }
        if(block>2)
        {
            printf("Case %d: -1\n",cas);
            continue;
        }
        ///bfs
        cnt=v.size();
        int mi=100000000;
        int tmp;
        for(int i=0;i<v.size();i++)
        {
            for(int j=i;j<v.size();j++)
            {
                memset(vis,false,sizeof(vis));
                if(i==j)
                {
                    while(!q.empty())q.pop();
                    t.x=v[i].first;
                    t.y=v[i].second;
                    t.step=0;
                    q.push(t);
                    vis[t.x][t.y]=true;
                    tmp=bfs();
                }
                else{
                    while(!q.empty())q.pop();
                    t.x=v[i].first;
                    t.y=v[i].second;
                    t.step=0;
                    q.push(t);
                    vis[t.x][t.y]=true;
                    t.x=v[j].first;
                    t.y=v[j].second;
                    t.step=0;
                    q.push(t);
                    vis[t.x][t.y]=true;
                    tmp=bfs();
                }
                if(tmp==-1)continue;
             //   printf("tmp=%d\n",tmp);
                mi=tmp<mi?tmp:mi;
            }
        }
        printf("Case %d: ",cas);
        if(mi==100000000)puts("-1");
        else printf("%d\n",mi);
    }
    return 0;
}
View Code

 

数牌

总共有52种牌面,用一个二维数组cnt[i][j]一次记录第j张 牌面为i 的牌的位置,用二分查找第k 张牌的位置。问题其实就是如何动态维护数组的有序性即 如 1 3 5 9 10 将5 改成11后数组依然要有序,可以用二维树状数组来维护,用二分查找找到第k张牌对应的位置。

提供一组测试数据

5

a3 a3 a3 a3 d2

4

1 1 5

2 1 a3

1 1 5

2 1 a3

树状数组保存牌的位置,数组维护的时间复杂度为mlog(n), 查询的时间复杂度为log(n), 所以总体时间复杂度为 mlog2(n)

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define low(x) x&(-x)
#define maxn 100010
int n,m;
int a[maxn];
int c[60][maxn];
void add(int k,int i,int val)
{
    while(i<maxn)
    {
        c[k][i]+=val;
        i+=low(i);
    }
}
int getsum(int k,int i)
{
    int sum=0;
    while(i>0)
    {
        sum+=c[k][i];
        i-=low(i);
    }
    return sum;
}
int getnum(char *s)
{
    int ans;
    ans=(s[0]-'a')*13;
    if(s[1]>='3'&&s[1]<='9')ans+=s[1]-'0'-2;
    else if(s[1]=='1'&&s[2]=='0')ans+=8;
    else if(s[1]=='J')ans+=9;
    else if(s[1]=='Q')ans+=10;
    else if(s[1]=='K')ans+=11;
    else if(s[1]=='A')ans+=12;
    else if(s[1]=='2')ans+=13;
    return ans;
}
int binarysearch(int k,int x)
{
    int l=0,r=maxn-1;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(getsum(k,mid)>=x)r=mid;
        else l=mid+1;
    }
    return r;
}
int main()
{
   // freopen("test.in","r",stdin);
   // freopen("test.out","w",stdout);
    while(~scanf("%d",&n))
    {
        char str[5];
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++)
        {
            scanf("%s",str);
            a[i]=getnum(str);
            add(a[i],i,1);
        }
        scanf("%d",&m);
        int op;
        while(m--)
        {
            scanf("%d",&op);
            if(op==1)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                if(a[x]==a[y])continue;
                add(a[x],x,-1);
                add(a[x],y,1);
                add(a[y],y,-1);
                add(a[y],x,1);
                a[x]^=a[y]^=a[x]^=a[y];
            }
            else
            {
                int num,k,sum;
                scanf("%d%s",&num,str);
                k=getnum(str);
                sum=getsum(k,maxn);
                if(num>sum)puts("-1");
                else printf("%d\n",binarysearch(k,num));
            }
        }
    }
    return 0;
}
View Code

 

组合数

lucas定理:Lucas(n,m,p)=c(n%p,m%p)*Lucas(n/p,m/p,p) ,p为素数。数据水

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,mod;
int c(int n,int m)
{
 
    if(n<m)return 0;
    int ans=1;
    int i=n,j=1;
    while(j<=m)
    {
        ans=ans*i/j;
        i--;
        j++;
    }
    return ans%mod;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&mod);
        int ans=1;
        while(n&&m)
        {
            ans=(ans*c(n%mod,m%mod))%mod;
            n/=mod;
            m/=mod;
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

组合数求余专场

 

posted on 2015-03-31 21:15  kylehz  阅读(222)  评论(0)    收藏  举报