NOIP模拟题 2016.11.18 [数论] [计数] [并查集]

第一题:信(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。


统计二进制位上的1的个数。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<iomanip>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<deque>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
#define maxx(x,y,z) max((x),max((y),(z)))
#define minn(x,y,z) min((x),min((y),(z)))
#define smax(x,y) x=max((x),(y))
#define smin(x,y) x=min((x),(y))
using namespace std;
template <class T> inline void read(T &x)
{
    x = 0;
    T flag = 1;
    char ch = (char) getchar();
    while(ch<'0' || ch>'9')
    {
        if(ch == '-') flag = -1;
        ch = (char) getchar();
    }
    while(ch>='0' && ch<='9')
    {
        x = (x<<1) + (x<<3) + (ch-'0');
        ch = (char) getchar();
    }
    x *= flag;
}
template <class T> T gcd(T a,T b) { return !b? a : gcd(b,a%b); }
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 100005;
const int maxd = 19;
const int D = 17;
int a[maxn];
LL b[maxn],c[maxn];
int cnt[maxd];
int n;
inline void print(LL a[])
{
    printf(AUTO,a[1]);
    for(int i=2;i<=n;i++) printf(" "AUTO,a[i]);
    putchar('\n');
}
int main()
{
    freopen("believe.in","r",stdin);
    freopen("believe.out","w",stdout);
    read(n);
    for(int i=1;i<=n;i++)
    {
        read(a[i]);
        for(int k=0;k<=D;k++) if(a[i]&(1<<k)) cnt[k]++;
    }
    for(int i=1;i<=n;i++)
        for(int k=0;k<=D;k++)
            if(a[i]&(1<<k)) b[i] += (LL)(1<<k)*cnt[k];
    for(int i=1;i<=n;i++)
        for(int k=0;k<=D;k++)
            if(a[i]&(1<<k)) c[i] += (LL)(1<<k)*n;
            else c[i] += (LL)(1<<k)*cnt[k];
    print(b);
    print(c);
    return 0;
}

第二题:心(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


并查集,如果构成环,那么可以取出这个环,每个点的度都是2。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<iomanip>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<deque>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
#define maxx(x,y,z) max((x),max((y),(z)))
#define minn(x,y,z) min((x),min((y),(z)))
#define smax(x,y) x=max((x),(y))
#define smin(x,y) x=min((x),(y))
using namespace std;
template <class T> inline void read(T &x)
{
    x = 0;
    T flag = 1;
    char ch = (char) getchar();
    while(ch<'0' || ch>'9')
    {
        if(ch == '-') flag = -1;
        ch = (char) getchar();
    }
    while(ch>='0' && ch<='9')
    {
        x = (x<<1) + (x<<3) + (ch-'0');
        ch = (char) getchar();
    }
    x *= flag;
}
template <class T> T gcd(T a,T b) { return !b? a : gcd(b,a%b); }
const int INF = 0x3f3f3f3f;
const int maxn = 200005;
const int N = 200000;
int fa[maxn];
int find(int x) { return x==fa[x]? x : fa[x]=find(fa[x]); }
inline bool union_find(int u,int v)
{
    int t1 = find(u);
    int t2 = find(v);
    if(t1 == t2) return false;
    fa[t2] = t1;
    return true;
}
int n,m;
int main()
{
    freopen("heart.in","r",stdin);
    freopen("heart.out","w",stdout);
    read(m); read(n); // n points with m edges
    for(int i=1;i<=N;i++) fa[i] = i;
    int ans = 0;
    for(int i=1;i<=m;i++)
    {
        int x,y;
        read(x); read(y);
        if(union_find(x,y)) 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(i)&x + a(i)|x = a(i) + x,可以想成两个集合,用Venn表示。
那么 n*a(i) + suma = b(i) + c(i)
可以推出 n*suma + n*suma = sumb + sumc
那么suma就可以求出了。
进而每一个a(i)都可以求出。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<iomanip>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<deque>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
#define maxx(x,y,z) max((x),max((y),(z)))
#define minn(x,y,z) min((x),min((y),(z)))
#define smax(x,y) x=max((x),(y))
#define smin(x,y) x=min((x),(y))
using namespace std;
template <class T> inline void read(T &x)
{
    x = 0;
    T flag = 1;
    char ch = (char) getchar();
    while(ch<'0' || ch>'9')
    {
        if(ch == '-') flag = -1;
        ch = (char) getchar();
    }
    while(ch>='0' && ch<='9')
    {
        x = (x<<1) + (x<<3) + (ch-'0');
        ch = (char) getchar();
    }
    x *= flag;
}
template <class T> T gcd(T a,T b) { return !b? a : gcd(b,a%b); }
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 100005;
const int D = 12; // less than 8192 = 2^13
int a[maxn],b[maxn],c[maxn];
int n;
inline void init()
{
    read(n);
    for(int i=1;i<=n;i++) read(b[i]);
    for(int i=1;i<=n;i++) read(c[i]);
}
inline void ERROR()
{
    puts("-1");
    exit(0);
}
void work()
{
    LL sumb = 0;
    LL sumc = 0;
    for(int i=1;i<=n;i++) sumb+=b[i],sumc+=c[i];
    LL suma = ((sumb+sumc)>>1)/n;
    if(suma*(n<<1) != sumb+sumc) ERROR();
    for(int i=1;i<=n;i++)
    {
        a[i] = (b[i]+c[i]-suma)/n;
        if(a[i]*n+suma != b[i]+c[i]) ERROR();
    }
}
inline void print()
{
    printf("%d",a[1]);
    for(int i=2;i<=n;i++) printf(" %d",a[i]);
    putchar('\n');
}
int main()
{
    freopen("problem.in","r",stdin);
    freopen("problem.out","w",stdout);
    init();
    work();
    print();
    return 0;
}

The last test before NOIP.
For over than 1 year, I’ve been fighting for the significant day,maybe two days..
It’s definitely a big day for me, but with the encouragement from my classmates, my teachers and the very unique person of you, it seems like everything’s stationary, the faith is in me, and I wanna remember every single piece of sunshine right now.
I believe I’ll work things out, and make everything ok. After this, there’ll be a new version of me. Whatever it takes, however it ends, I’ll always be alright just because you’re always there for me.
Whether tou see this or not, these words are from the bottom of my heart, and thank you Vikka :)

2016.11.18 14:45

原创文章 152 获赞 15 访问量 6万+

猜你喜欢

转载自blog.csdn.net/ourfutr2330/article/details/53216442
今日推荐