码迷,mamicode.com
首页 > 其他好文 > 详细

15th浙大校赛 zoj3860-3868

时间:2015-04-13 22:16:52      阅读:173      评论:0      收藏:0      [点我收藏+]

标签:

比赛链接: here

题目对应到ZOJ3860~3868

Find the Spy

 水

技术分享
#include<cstdio>
#include<map>
#include<cstring>
#include<iostream>
using namespace std;
map<int,int>mp;
map<int,int>::iterator it;
int main()
{
    int T,n,x;
    scanf("%d",&T);
    while(T--)
    {
        mp.clear();
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&x);
            mp[x]++;
        }
        for(it=mp.begin();it!=mp.end();it++)
        {
            if(it->second==1)printf("%d\n",it->first);
        }
    }
    return 0;
}
View Code

Valid Pattern Lock

 水 dfs 

 3*3的九宫格,给你其中n个点按下面要求连起来:

1. 给你的n个点都要激活(至少经过一次)

2. 如果点A,B相连后要经过另一个点C,则C在序列中的位置必须在A,B之前 如 1 7 4是不合法的

3.线段相交是没关系的,如 7 6 9 4

A B线段中有点C的情况

1. AB行号相差2并且列号一样 C=(A+B)/2

2.AB列号相差2并且行号一样 C=(A+B)/2

3.AB行号和列号都相差2(对角)C=(A+B)/2

由于要多次用到abs运算和行列号的运算,可以先把运算结果存起来

技术分享
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int x[10],y[10];
int re[5][5];
int a[10];
int n;
bool vis[10];
int cnt;
int s[10];
void dfs(int pre,int num,int op)
{
//    printf("%d %d\n",pre,num);
    int i,t;
    if(num==n)
    {
        if(op){
            for(i=0;i<n-1;i++)printf("%d ",s[i]);
            printf("%d\n",s[n-1]);
        }
        cnt++;
        return;
    }

    for(i=0;i<n;i++)
    {
        if(!vis[a[i]])
        {
            if(re[x[a[i]]][x[pre]]==2||re[y[a[i]]][y[pre]]==2)
            {
                t=(pre+a[i])>>1;
                if(vis[t])
                {
                    vis[a[i]]=true;
                    s[num]=a[i];
                    dfs(a[i],num+1,op);
                    vis[a[i]]=false;
                }
            }
            else
            {
                vis[a[i]]=true;
                s[num]=a[i];
                dfs(a[i],num+1,op);
                vis[a[i]]=false;
            }
        }
    }
}
int main()
{
    int T,i,j;
    for(i=1;i<10;i++)x[i]=(i-1)/3;
    for(i=1;i<10;i++)y[i]=(i-1)%3;
    for(i=0;i<3;i++)
    {
        for(j=0;j<3;j++)
            re[i][j]=abs(i-j);
    }
    scanf("%d",&T);
    while(T--)
    {

        scanf("%d",&n);
        for(i=0;i<n;i++){
            scanf("%d",&a[i]);
        }
        sort(a,a+n);
        cnt=0;
        for(i=0;i<n;i++){
            memset(vis,false,sizeof(vis));
            vis[a[i]]=true;
            s[0]=a[i];
            dfs(a[i],1,0);
        }
        printf("%d\n",cnt);
        for(i=0;i<n;i++){
            memset(vis,false,sizeof(vis));
            vis[a[i]]=true;
            s[0]=a[i];
            dfs(a[i],1,1);
        }
    }
    return 0;
}
View Code

 

Intersection

看了解题报告后发现这题也是水题

题意:

按1-2n的编号给定2n个点以及n条线段,每个点属于且仅属于一条线段。

线段用端点的编号确定。

现在一次操作可以交换两个点的编号

要求在不超过n+10次的操作后使得任意两条线段不相交。

输入保证任意两个点不重合,任意三个点不相交。

思路:

首先要明确,不是要求最少操作次数,只要不超过n+10次就可以。

所以一定有解:

step 1: 点配对

    把所有点按水平序排好,人为配对:排名2k-1的点和排名2k的点组成一条线段。(2k-1并不是点的编号,只是排序后的位置)

    这样的话没有线段会相交。

step 2: 统计操作次数

    点已经配好了,只要计算从原来的配对变成现在的配对需要多少次操作。

    假设排序后的点编号是:a, b, ... , c, ... , d , ....

    本来是a和c组成一条线段,b和d组成一条线段

    为了让a和c配对,交换b和c的编号(其实是交换b和c对应的点坐标。。。)

    显然最多进行n次操作

 

把握一点:操作之后,点的编号对应关系不变。

比如说1号点一开始与4号点组成线段,操作之后还是1号点和4号点组成线段

但是1号点和4号点的坐标可能和之前不一样

理解这一点就好了。。。

技术分享
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define maxn 200020
struct ss
{
    int x, y ,id;
    ss(){}
    ss(int _x,int _y):x(_x),y(_y){}
}p[maxn];
int f[maxn];
int rk[maxn];
int n;
bool cmp(ss a,ss b)
{
    if(a.x==b.x)return a.y<b.y;
    return a.x<b.x;
}
vector<ss>v;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        v.clear();
        scanf("%d",&n);
        for(int i=1;i<=2*n;i++){
            scanf("%d%d",&p[i].x,&p[i].y);
            p[i].id=i;
        }
        int a,b;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&a,&b);
            f[a]=b;f[b]=a;
        }
        sort(p+1,p+2*n+1,cmp);
        for(int i=1;i<=2*n;i++){
           rk[p[i].id]=i;
        }
        for(int i=1;i<=2*n;i+=2){
            int a=p[i].id,b=p[i+1].id;
            if(f[a]!=b)
            {
                int c=f[a],d=f[b];
                v.push_back(ss(b,c));
                swap(p[i+1].id,p[rk[c]].id);
                swap(rk[b],rk[c]);
            }
        }
        printf("%d\n",v.size());
        for(int i=0;i<v.size();i++)
        {
            printf("%d %d\n",v[i].x,v[i].y);
        }
    }
    return 0;
}
View Code

 鸟神的极角排序代码:

极角排序后相邻的两点为一组

技术分享
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
#include <math.h>
#include <string>
#include <vector>
using namespace std;

#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clr( a , x ) memset ( a , x , sizeof a )

const int MAXN = 200005 ;

struct Point {
    int x , y , idx ;
    double r ;
    Point () {}
    Point ( int x , int y ) : x ( x ) , y ( y ) {}
    bool operator < ( const Point& a ) const {
        return r < a.r ;
    }
} ;

struct Node {
    int x , y ;
    Node () {}
    Node ( int x , int y ) : x ( x ) , y ( y ) {}
} ;

Point p[MAXN] ;
int idx[MAXN] ;
int idxf[MAXN] ;
Node q[MAXN] ;
Node ans[MAXN] ;
int top ;
int n ;

bool cmp ( const Point& a , const Point& b ) {
    return a.idx < b.idx ;
}

void solve () {
    int x , y ;
    top = 0 ;
    scanf ( "%d" , &n ) ;
    rep ( i , 0 , 2 * n ) {
        scanf ( "%d%d" , &p[i].x , &p[i].y ) ;
        p[i].x += 1e9 ;
        p[i].y += 1e9 ;
        p[i].r = atan2 ( p[i].y , p[i].x ) ;
        p[i].idx = i ;
    }
    sort ( p , p + 2 * n ) ;
    rep ( i , 0 , 2 * n ) {
        idx[p[i].idx] = i ;
        idxf[i] = p[i].idx ;
    }
    //rep ( i , 0 , 2 * n ) printf ( "---%d %d %d %d\n" , p[i].idx , i , idx[p[i].idx] , idxf[i] ) ;
    sort ( p , p + 2 * n , cmp ) ;
    For ( i , 1 , n ) {
        scanf ( "%d%d" , &x , &y ) ;
        -- x ;
        -- y ;
        x = p[x].idx ;
        y = p[y].idx ;
        //printf ( "%d %d\n" , x , y ) ;
        int xx = idx[x] % 2 ;
        int yy = idx[y] % 2 ;
        //printf ( "xx = %d yy = %d\n" , idx[x] , idx[y] ) ;
        int t ;
        if ( !xx && idx[x] + 1 == idx[y] || xx && idx[x] - 1 == idx[y] ) continue ;
        if ( !xx ) t = idx[x] + 1 ;
        else t = idx[x] - 1 ;
        //printf ( "------------%d %d\n" , y , t ) ;
        ans[++ top] = Node ( y , idxf[t] ) ;
        int tmp = idx[y] ;
        swap ( idx[y] , idx[idxf[t]] ) ;
        swap ( idxf[tmp] , idxf[t] ) ;
        //printf ( "%d %d\n" , idxf[idx[x]] , idxf[idx[y]] ) ;
    }
    printf ( "%d\n" , top ) ;
    For ( i , 1 , top ) printf ( "%d %d\n" , ans[i].x + 1 , ans[i].y + 1 ) ;
}

int main () {
    int T ;
    scanf ( "%d", &T ) ;
    For ( i , 1 , T ) solve () ;
    return 0 ;
}
View Code

Paths on the Tree

留个坑!!!!待填。

 

Quiz for EXO-L

 水题 dfs 比赛时没时间看

就是求连通块的个数,把每种图像的黑色块个数和白色块个数数出来就行了

其中Sehun,Xiumin 黑色块为5 ,白块为2 一样,则用面积比(最大黑色块:最小黑色块来判断)

注意900*900=810000,早就暴栈了,手动扩展也没用!dfs时用队列存储状态即可。

技术分享
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
int mp[1000][1000];
int n,m;
int s[2];
bool vis[1000][1000];
int dx[9]={-1,-1,-1,0,0,1,1,1};
int dy[9]={-1,0,1,-1,1,-1,0,1};
int sum,mini,maxi;
queue<pair<int,int> >q;
void dfs(int x,int y,int op)
{
    while(!q.empty())q.pop();
    q.push(make_pair(x,y));
    vis[x][y]=true;
    while(!q.empty())
    {
        int xx,yy;
        x=q.front().first;
        y=q.front().second;
        q.pop();
        sum++;
        for(int i=0;i<8;i++)
        {
            xx=x+dx[i];
            yy=y+dy[i];
            if(xx>=0&&xx<n&&yy>=0&&yy<n&&mp[xx][yy]==op&&!vis[xx][yy])
            {
                q.push(make_pair(xx,yy));
                vis[xx][yy]=true;
            }
        }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {

        int flag=1;
        int x,id=0;
        scanf("%d%d",&n,&m);
        while(m--)
        {
            scanf("%d",&x);
            while(x--)
            {
                mp[id/n][id%n]=flag;
                id++;
            }
            flag=!flag;
        }
        s[0]=0;
        memset(vis,false,sizeof(vis));
        mini=100000;maxi=0;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(mp[i][j]==0&&!vis[i][j]){
                    s[0]++;
                    sum=0;
                    dfs(i,j,0);
                    if(sum<mini)mini=sum;
                    if(sum>maxi)maxi=sum;
                }
            }
        }
        s[1]=0;
        memset(vis,false,sizeof(vis));
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(mp[i][j]==1&&!vis[i][j]){
                    s[1]++;
                    dfs(i,j,1);
                }
            }
        }
        if(s[0]==9&&s[1]==2)puts("Baekhyun");
        if(s[0]==5&&s[1]==1)puts("Chanyeol");
        if(s[0]==1&&s[1]==3)puts("Chen");
        if(s[0]==1&&s[1]==2)puts("D.O");
        if(s[0]==2&&s[1]==13)puts("Kai");
        if(s[0]==3&&s[1]==1)puts("Kris");
        if(s[0]==6&&s[1]==2)puts("Lay");
        if(s[0]==5&&s[1]==8)puts("Luhan");
        if(s[0]==2&&s[1]==8)puts("Suho");
        if(s[0]==2&&s[1]==4)puts("Tao");
        if(s[0]==5&&s[1]==2){
            if(mini*20<maxi)puts("Sehun");
            else puts("Xiumin");
        }
    }
    return 0;
}
/*
2
6 13
7 2 1 1 2 3 4 1 4 1 1 2 7

ca1 131 1194
ca2 53 1646
*/
View Code

Superbot

 水 bfs 

只不过状态用vis[20][20][4]来记录,每个点都有四个状态,访问过就不能访问

通过控制面板控制机器人找钻石,控制面板每p时间右移一次(队尾变队首),求最短路径

控制面板为左右上下的顺序,初始时 光标在左

有3种操作,占用一个单位时间

1. 光标左移(最左的移到最右)或者右移(最右的移到最左)

2.按按钮,机器人会根据光标所指的方向移动一个单位

3.停在原地

技术分享
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
int n,m,p;
char mp[20][20];
int sx,sy,ex,ey;
//l(0) r(1) u(2) d(3)
int dx[4]={0,0,-1,1};
int dy[4]={-1,1,0,0};
bool vis[20][20][4];
struct ss
{
    int x,y;
    int step;
    int dir;
    ss(){}
    ss(int _x,int _y,int _step,int _dir):x(_x),y(_y),step(_step),dir(_dir){}
}t;
queue<ss>q;
void bfs()
{
    int x,y,step,dir,time;
    while(!q.empty())q.pop();
    t=ss(sx,sy,0,0);
    q.push(t);
    while(!q.empty())
    {
        t=q.front();
        q.pop();
        if(t.x==ex&&t.y==ey)
        {
            printf("%d\n",t.step);
            return;
        }
        if(t.step&&t.step%p==0)
        {
            t.dir=(t.dir+3)%4;
        }
        if(vis[t.x][t.y][t.dir])continue;
        vis[t.x][t.y][t.dir]=true;

        x=t.x+dx[t.dir];
        y=t.y+dy[t.dir];
        step=t.step+1;
        dir=t.dir;
        if(x>=0&&x<n&&y>=0&&y<m&&mp[x][y]!=*)
        {
            q.push(ss(x,y,step,dir));
        }

        x=t.x;
        y=t.y;
        step=t.step+1;
        dir=t.dir;
        q.push(ss(x,y,step,dir));

        x=t.x;
        y=t.y;
        step=t.step+1;
        dir=(t.dir+1)%4;
        q.push(ss(x,y,step,dir));

        x=t.x;
        y=t.y;
        step=t.step+1;
        dir=(t.dir+3)%4;
        q.push(ss(x,y,step,dir));
    }
    puts("YouBadbad");
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int i,j;
        scanf("%d%d%d",&n,&m,&p);
        for(i=0;i<n;i++){
            scanf("%s",mp[i]);
            for(j=0;j<m;j++)
            {
                if(mp[i][j]==@)
                {
                    sx=i;
                    sy=j;
                }
                else if(mp[i][j]==$)
                {
                    ex=i;
                    ey=j;
                }
            }
        }
        memset(vis,false,sizeof(vis));
        bfs();
    }
    return 0;
}
View Code

Cylinder Candy

 几何体,留个坑!!!!待填。

先把公式存着以后慢慢推

技术分享

技术分享

Earthstone: Easy Version

 水

技术分享
#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<cstdlib>
using namespace std;
const int maxn=22222;
const int inf=9999999999;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int a,b,A,B;
        cin>>a>>b>>A>>B;
        if(a==0) {cout<<"Invalid"<<endl;continue;}
        b=b-A;
        B=B-a;
        if(b<=0&&B>0) cout<<"Discard"<<" "<<A<<" "<<B<<endl;
        else if(b>0&&B<=0) cout<<a<<" "<<b<<" Discard"<<endl;
        else if(b>0&&B>0)cout<<a<<" "<<b<<" "<<A<<" "<<B<<endl;
        else cout<<"Discard Discard"<<endl;
    }    
    return 0;
}
View Code

GCD Expectation

脑洞题

暴力统计。

比如用dp[i] 表示gcd为i的子集个数。

那么如果i的倍数有x个, 那么gcd为 i的倍数的子集个数就是 2^x - 1。

要算gcd恰好为i的,那么就减掉就好。

dp[i] = 2^x - 1;   for(int j = i+i;j <= Max;j += i) dp[i] -= dp[j];

倒过来求dp[i]就好。 复杂度就是调和级数的复杂度nln n.

简单题啊。

技术分享
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define maxn 1000010
#define mod 998244353
#define ll long long
int a[maxn];
ll dp[maxn];
ll b[maxn];
ll pow_m(ll a,ll n)
{
    ll ret=1;
    ll tmp=a;
    while(n)
    {
        if(n&1)ret=ret*tmp%mod;
        tmp=tmp*tmp%mod;
        n>>=1;
    }
    return ret;
}
int main()
{
    int n,k,T;
    scanf("%d",&T);
    while(T--)
    {
        memset(b,0,sizeof(b));
        scanf("%d%d",&n,&k);
        int ma=0;
        for(int i=0;i<n;i++){
                scanf("%d",&a[i]);
                ma=max(ma,a[i]);
                b[a[i]]++;
        }
        ll ans=0;
        for(int i=ma;i>=1;i--)
        {
            dp[i]=0;
            ll cc=0;
            for(int j=i;j<=ma;j+=i)
            {
                cc+=b[j];
                if(j>i)dp[i]=(dp[i]-dp[j]+mod)%mod;
            }
            dp[i]=(dp[i]+pow_m(2,cc)-1)%mod;
            //printf("%d %d\n",i,dp[i]);
            ans+=dp[i]*pow_m(i,k)%mod;
            ans%=mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

15th浙大校赛 zoj3860-3868

标签:

原文地址:http://www.cnblogs.com/kylehz/p/4420009.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!