11月18日——离noip还有1天[游戏王YGO]

今天有人品爆发,240分,但是第三题没特判,第一题没用高精度也是可以GG的……
明天就是NOIP了,高一党就全当体会一下吧!(P.S.今天有两个高一的来考试(不听劝啊~),于是乎……但愿没影响到他们考试的心情)

每日推荐!

没错,这次的每日推荐就是游戏王!!!
从小学二年级开始,我看见了游戏王的起起伏伏,也经历了从萌新到菜鸟,再到现在的一般般的水平,用游戏王作为我今年noip的最后一份推荐,就是想贯彻游戏王决斗中除强大的计算外更吸引我的精神,never give up!!
所以这次就以一句帅气的话来告诉世界,高一党有我在,而我也一定要创造奇迹!!!!(这flag立的………………)
than :: 所列哇多噶那!!!(千星大大快更新!!!!)
这里写图片描述
这里写图片描述

第一题:信(believe.cpp/c/pas)

背景描述:
这里写图片描述

一切死亡都有冗长的回声
—— 《一切》北岛

给定一个N个元素的序列A,
定义Bi = (Ai and A1) + (Ai and A2) + (Ai and A3)+ …… + (Ai and An)
定义Ci = (Ai or A1) + (Ai or A2) + … + (Ai or An)
求B和C序列。
输入格式:
第一行一个整数N表示序列长度
接下来一行N个整数, 第i个整数为Ai
输出格式:
第一行N个整数输出B序列
第二行N个整数输出C序列

样例输入:
4
3 5 1 1
样例输出:
6 8 4 4
16 22 10 10
数据规模:
对于50%的数据, N <= 1000
对于100%的数据, N <= 100000, Ai <= 100000
注意事项:
输入量较大, 请使用比较快的例如scanf的读入方式, 最好不要采用cin。//使用读入优化readin();注:template< class T >

思考与题解

第一题:
考虑每一位对每个数的贡献, 令cnt[i]为二进制第i位为1的数的个数。
如果第j个数, 第i位为1, 那么第i位对Bj的贡献为cnt[i] * (1 << i), 对Cj的贡献 为n * (1 << i)
否则, 对Bj的贡献为0, 对Cj的贡献为cnt[i] * (1 << i)
复杂度N*logV, V代表值域
题解已经写得很清晰了……小编就不再赘述了。

code

呜呜呜~~没有标答快……

#include<set>
#include<list>
#include<deque>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<string>
#include<vector>
#include<ctime>
#include<stack>
#include<map>
#define Li(x) x<<1
#define Ri(x) x<<1|1
#define clr(x) memset((x),0,sizeof(x))
#define cld(x) memset((x),127/2,sizeof(x))
#define smin(x,y) x=min(x,y)
#define smax(x,y) x=max(x,y)
#define smin(x,y) x=min(x,y)
#define fmax(x,y,z) max(x,max(z,y))
#define fmin(x,y,z) min(x,min(z,y))
#define res(i,x,y) for(int i=x;i<=y;i++)
#define rez(i,x,y) for(int i=x;i>=y;i--)
#define resl(i,x,y) for(ll i=x;i<=y;i++)
#define rezl(i,x,y) for(ll i=x;i>=y;i--)
#define INF 2100000000
#define MOD 1000000007
#define ll long long
#define N 200010
#define P 65536
#ifdef win32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
template <class T>
inline void readin(T &resez){
    static char ch;
    while((ch=getchar())<'0'||ch>'9');
        resez=ch-48;
    while((ch=getchar())>='0'&&ch<='9')
        resez=resez*10+ch-48;
}
const ll M = 1e5+10;
ll n,num[21],s[M],a,C[M],B[M],cnt[21];
ll power(ll a,ll b){
    ll ans=1;
    while(b){
        if(b%2==1){
            ans=ans*a;
        }
        a=a*a;
        b/=2;
    }
    return ans;
}
int main(){
    freopen("beleive.in","r",stdin);
    freopen("believe.out","w",stdout);
    readin(n);
    resl(i,1,n){
        readin(a);
        resl(j,0,17){
            if((1<<j)&a) num[j]++; 
            else cnt[j]++;
        }
        s[i]=a;
    }
    resl(i,1,n){
        resl(j,0,17){
            if((1<<j)&s[i]){
                B[i]+=power(2,j)*(num[j]);
            }
        }
        cout<<B[i]<<' ';
    } 
    printf("\n");
    resl(i,1,n){
        resl(j,0,17){
            if((1<<j)&s[i]) {
                C[i]+=power(2,j)*(num[j]+cnt[j]);
            }
            else{
                C[i]+=power(2,j)*(num[j]);
            }
        }
        cout<<C[i]<<' ';
    }
    return 0;
} 

标答

这次标答的却比所有人都优……

//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#ifdef WIN32
#define LLD "%I64d"
#else
#define LLD "%lld"
#endif

using namespace std ;

int n ;

const int MAXN = 100010 ; 

typedef long long LL ; 

int cnt[MAXN], a[MAXN] ;

LL b[MAXN], c[MAXN]; 

int main() {
        freopen("beleive.in", "r", stdin) ;
        freopen("believe.out", "w", stdout) ; 
        scanf("%d", &n) ; 
        for (int i = 1; i <= n; i ++) scanf("%d", &a[i]) ; 
        for (int i = 1; i <= n; i ++) { 
                for (int j = 0; j < 20; j ++) {
                        if ((a[i] >> j) & 1) cnt[j] ++ ; 
                }
        }
        for (int i = 1; i <= n; i ++) {
                for (int j = 0; j < 20; j ++) { 
                        if ((a[i] >> j) & 1) {
                                b[i] += 1LL * cnt[j] * (1 << j) ; 
                                c[i] += 1LL * n * (1 << j) ; 
                        }
                        else {
                                c[i] += 1LL * cnt[j] * (1 << j) ; 
                        }
                }
        }
        for (int i = 1; i <= n; i ++) {
                printf(LLD "%c", b[i], (i == n ? 10 : ' ')) ; 
        }       
        for (int i = 1; i <= n; i ++) {
                printf(LLD "%c", c[i], (i == n ? 10 : ' ')) ; 
        }
}

第二题:心(heart.cpp/c/pas)

这里写图片描述

背景描述:

不是一切深渊都是灭亡
不是一切灭亡都覆盖在弱者的头上
——《这也是一切》 舒婷

有N个透明的盒子, 每个盒子里面有两个不同颜色的球, 总共有M种颜色。
Alice和Bob又在玩游戏, 具体的, Alice会从N个盒子里面选出若干个, Bob再从Alice选出的盒子里面选出一些(不能不选), 如果在Bob选出的盒子中, 每个颜色的球都总共出现了偶数次(0次也是偶数次), 那么Bob胜利, 否则Alice胜利
在Alice和Bob都足够聪明的情况下, Alice想知道自己在能够获胜的前提下, 第一次最多可以选出几个盒子
输入格式:
第一行有两个整数N和M, 意义如题
接下来N行, 第i+1行两个整数表示第i+1个盒子里面的两个球分别是什么颜色的
输出格式:
一行一个整数表示Alice最多可以选多少个盒子

样例输入:
3 3
1 2
2 3
2 3
样例输出:
2
数据规模: 对于30%的数据, N <= 10
对于50%的数据, N <= 20
对于100%的数据, N <= 100000, M <= 2N

思考与题解

第二题:
将每一种颜色的球看成点, 那么一个盒子就是一条连接两个点的边。
选出的盒子如果构成了环, 那么Bob胜, 否则Alice胜
也就是说我们现在要选出尽量多的边, 使得不存在环, 直接并查集即可
并查集在此处

code

小编是通过建图来解决的………………很慢…………

#include<set>
#include<list>
#include<deque>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<string>
#include<vector>
#include<ctime>
#include<stack>
#include<map>
#define Li(x) x<<1
#define Ri(x) x<<1|1
#define clr(x) memset((x),0,sizeof(x))
#define cld(x) memset((x),127/2,sizeof(x))
#define smin(x,y) x=min(x,y)
#define smax(x,y) x=max(x,y)
#define smin(x,y) x=min(x,y)
#define fmax(x,y,z) max(x,max(z,y))
#define fmin(x,y,z) min(x,min(z,y))
#define res(i,x,y) for(int i=x;i<=y;i++)
#define rez(i,x,y) for(int i=x;i>=y;i--)
#define INF 2100000000
#define MOD 1000000007
#define ll long long
#define N 200010
#define P 65536
#ifdef win32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
const int M = 2e5+5;
int n,m,a,b,be[M],tot,num[M],ans;
template <class T>
inline void readin(T &resez){
    static char ch;
    while((ch=getchar())<'0'||ch>'9');
        resez=ch-48;
    while((ch=getchar())>='0'&&ch<='9')
        resez=resez*10+ch-48;
}
struct Edge{
    int from,to;
    int belong;
}edge[M];
vector<int> g[M];
void dfs(int s){
    for (int i=0;i<g[s].size();i++){
        int v=g[s][i];
        if(!be[v]){
            be[v]=be[s];
            dfs(v);
        }
    }
}
int main(){
    freopen("heart.in","r",stdin);
    freopen("haert.out","w",stdout);
    cin>>n>>m;
    res(i,1,n){
        readin(a);readin(b);
        g[a].push_back(b);g[b].push_back(a);
        edge[i].to=a;edge[i].from=b;
    }
    res(i,1,m){
        if(!be[i])be[i]=++tot;
        dfs(i);
    }
    res(i,1,m)num[be[i]]++;
    res(i,1,tot)ans+=num[i]-1;
    cout<<ans;
    return 0;
} 

反正能AC

李ys的神奇代码

但是标答或者说是更快的方法是李ys大神所用的并查集(Kruskal)就可以达到最快!!!

#include<iostream>
#include<cstdio>
#include<ctime>
#include<algorithm>
using namespace std;
const int MAX=100000*4;
int fa[MAX],ans,n,m;
int findfa(int k)
{
    if (fa[k]==k) return k;
    return fa[k]=findfa(fa[k]);
}
inline int read()
{
    char x=(char)getchar();
    int re=0;
    while (x<='9'&&x>='0')
    {
        re=re*10+x-48;
        x=getchar();
    }
    return re;
}
int main()
{
    freopen("heart.in","r",stdin);
    freopen("haert.out","w",stdout);
    n=read();m=read();
    for (int i=1;i<=m;i++) fa[i]=i;
    for (int i=1;i<=n;i++)
    {
        int x=read(),y=read();
        int f1=findfa(x);
        int f2=findfa(y);
        if (f1!=f2)
        {
            fa[f1]=f2;
            ans++;
        }
    }
    printf("%d",ans);
    return 0;
}

第三题:题(problem.cpp/c/pas)

这里写图片描述
背景描述:
黑夜给了我黑色的眼睛
我却用它寻找光明
——《一代人》 顾城
已知一个N个元素的非负整数序列A,
定义Bi = (Ai and A1) + (Ai and A2) + (Ai and A3)+ …… + (Ai and An)
定义Ci = (Ai or A1) + (Ai or A2) + … + (Ai or An)
给出B和C序列, 构造一个满足条件的A序列, 如果没有, 输出-1
输入格式:
第一行一个整数N。
接下来一行N个整数表示B序列
接下来一行N个整数表示C序列
输出格式:
如果有解, 输出一行N个整数表示你构造的A序列, SPJ很脆弱, 所以你构造的序列每个整数必须在[0,8191]这个区间内, 我们保证如果有解, 那么一定存在一个解满足每个元素均在[0,8191]内
否则输出-1

样例输入:
4
6 8 4 4
16 22 10 10
样例输出:
3 5 1 1
数据规模:
对于30%的数据, N = 2
对于70%的数据, N <= 200
对于100%的数据, N <= 100000, Bi , Ci<= 1000000000

题解

第三题:
第三题是第一题倒过来。
注意到对于任意两个非负整数A, B。 A and B + A or B = A + B
于是Bi+Ci = A1 + A2 + ….. + An + Ai * n
我们可以把所有数求和, 得到Ai的和, 记为sum, 再对每个数用Bi+Ci-sum / n 可以得到Ai
最后跑一遍第一题判定一下是否合法即可
值域在0到8191只是为了随机数据随出来B和C都在1e9以内, 没有实际意义

听小编一言,上诉都是渣渣!!!!!
看小编的代码!!!!!

code(垃圾标程)

//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std ;

int n ;

const int MAXN = 200010 ;

typedef long long LL ;

int B[MAXN], C[MAXN], a[MAXN]; 

LL b[MAXN], c[MAXN] ;

struct Node {
        int b, c, id ;
        bool operator < (const Node ano) const {
                return b + c < ano.b + ano.c ;
        }
} opt[MAXN] ; 

int cnt[MAXN] ;
bool check(int x) { 
        int now = x ; 
        for (int i = 1; i <= n; i ++) { 
                a[opt[i].id] = now ; 
                now += ((opt[i + 1].b + opt[i + 1].c - opt[i].b - opt[i].c) / n) ; 
        }
        memset(cnt, 0, sizeof cnt) ; 
        memset(b, 0, sizeof b) ;
        memset(c, 0, sizeof c) ;
        for (int i = 1; i <= n; i ++) { 
                for (int j = 0; j < 20; j ++) {
                        if ((a[i] >> j) & 1) cnt[j] ++ ; 
                }
        }
        for (int i = 1; i <= n; i ++) {
                for (int j = 0; j < 20; j ++) { 
                        if ((a[i] >> j) & 1) {
                                b[i] += 1LL * cnt[j] * (1 << j) ; 
                                c[i] += 1LL * n * (1 << j) ; 
                        }
                        else {
                                c[i] += 1LL * cnt[j] * (1 << j) ; 
                        }
                }
        }
        return b[1] + c[1] >= B[1] + C[1] ; 
}

bool check2(int x) { 
        int now = x ; 
        for (int i = 1; i <= n; i ++) { 
                a[opt[i].id] = now ; 
                now += ((opt[i + 1].b + opt[i + 1].c - opt[i].b - opt[i].c) / n) ; 
        }
        memset(cnt, 0, sizeof cnt) ; 
        memset(b, 0, sizeof b) ;
        memset(c, 0, sizeof c) ; 
        for (int i = 1; i <= n; i ++) { 
                for (int j = 0; j < 20; j ++) {
                        if ((a[i] >> j) & 1) cnt[j] ++ ; 
                }
        }
        for (int i = 1; i <= n; i ++) {
                for (int j = 0; j < 20; j ++) { 
                        if ((a[i] >> j) & 1) {
                                b[i] += 1LL * cnt[j] * (1 << j) ; 
                                c[i] += 1LL * n * (1 << j) ; 
                        }
                        else {
                                c[i] += 1LL * cnt[j] * (1 << j) ; 
                        }
                }
        }
        for (int i = 1; i <= n; i ++) { 
                if ((b[i] != B[i]) || (c[i] != C[i])) return 0 ; 
        }
        return 1;  
}



int main() { 
        freopen("problem.in", "r", stdin) ; 
        freopen("problem.out", "w", stdout) ; 
        scanf("%d", &n) ; 
        for (int i = 1; i <= n; i ++) scanf("%d", &opt[i].b), B[i] = opt[i].b, opt[i].id = i  ;
        for (int i = 1; i <= n; i ++) scanf("%d", &opt[i].c), C[i] = opt[i].c ; 
        sort(opt + 1, opt + n + 1) ;
        for (int i = 2; i <= n; i ++) {
                if ((opt[i].b + opt[i].c - opt[i - 1].b - opt[i - 1].c) % n != 0) {
                        puts("-1") ;
                        return 0 ; 
                }
        }
        int l = 0, r = 8191 ; 
        while (l < r) {
                int mid = (l + r) >> 1; 
                if (check(mid) ) r = mid ;
                else l = mid + 1 ; 
        }
        if (check2(l)) {
                for (int i = 1; i <= n; i ++) printf("%d%c", a[i], (i == n ? 10 : ' ')) ;
        }
        else puts("-1") ;
}

xc大大的O(n)解法

A+B=A&B+A|B

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define name "problem"
#define maxn 100009
typedef long long ll;
using namespace std;
ll b[maxn],c[maxn],a[maxn];
void get(ll &y) {
    y=0;
    char x=getchar();
    while('0'>x||x>'9')
        x=getchar();
    while('0'<=x&&x<='9')   {
        y=y*10+x-'0';
        x=getchar();
    }
}
int main()  {
    freopen(name".in","r",stdin);
    freopen(name".out","w",stdout);
    ll n;
    get(n);
    ll sum=0;
    for(int i=1;i<=n;i++)   {
        get(b[i]);
        sum+=b[i];
    }
    for(int i=1;i<=n;i++)   {
        get(c[i]);
        sum+=c[i];
    }
    if(sum%(2*n)==0)
        sum/=2*n;
    else {
        cout<<-1<<endl;
        return 0;
    }
    for(int i=1;i<=n;i++)   {
        if((b[i]+c[i]-sum)%n==0)
            a[i]=(b[i]+c[i]-sum)/n;
        else    {
            cout<<-1<<endl;
            return 0;
        }
    }
    for(int i=1;i<=n;i++)   {
        cout<<a[i]<<(i==n ? "\n" : " ");
    }
}

总结

今天也无力回天了……
面对现实吧,小编自己只是个渣渣……………………
然后预祝所有的OIer考试顺利!!!
(自己更加顺利!!!!!)
(没有高精度!!!)
(今天忘发图!!!)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值