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

【学长虐学弟欢乐赛系列】Round1

时间:2015-02-28 18:47:37      阅读:261      评论:0      收藏:0      [点我收藏+]

标签:省选模拟赛

第一套题
出题人:Time-Machine
目标地址:Time-Machine学长的blog
试题下载地址
数据下载地址
据说题目难度T3<T1<T2 这不科学QAQ
光荣爆零QwQ奇怪的错误是说不尽的

T1 Hope

主要题干:首先你列出了两个长度为 n 的数表 a[],b[],其中每个数 a[i]用二进制表示一个集合。例如数字 5=( 101) 2 就代表集合{1,3}。第 i 次实验会准备一个小盒子,里面装着集合 a[i]所有非空子集的纸条,然后苗木诚会从中摸一张纸条。如果满足他摸的这张纸条是 a[i]的子集而不是 a[i-b[i] ~ i-1]任意一个的子集,那么他就胜利。令你没想到的是,他居然一次也没赢。在嘲讽他之余,为了知道这件事发生的概率,你想要算出每次实验有多少纸条能使他获胜

测试时候异或乱搞本来觉得应该能骗个几十分结果最后爆零了QAQ当时就做这一个题还炸了QAQ

标算:暴力枚举每个数的所有子集,用一个数组记录下每一个可能出现的子集上一次出现的编号.

//Std by Time-Machine  
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N = 1e5+10;
int n,m,f[N];
int scan(){int i=0;scanf("%d",&i);return i;}
int main(){
    int i,j,k,a,b;
    freopen("hope.in","r",stdin);
    freopen("hope.out","w",stdout);
    n = scan();
    int t,ans;
    for(i=1;i<=n;i++){
        a = scan();b = scan();
        t = a;
        ans =0;
        do{
            if(f[t] < i-b)ans++;
            f[t] = i;
            t = a&(t-1);
        }while(t);
        printf("%d\n",ans);
    }
    return 0;
}

T2 Copy
主要题干:
现在他找到了 n 个最仰慕的神犇(同样用 n 个数字 a[i]表示), 他希望通过变
换让自己的第 i 个人格和第 i 个神犇一模一样。
小 T 不能随意改变自己的人格,只能通过 m 次形如“b[i]^=b[j]”的操作来改变自己的人格。
【输出】
如果存在合法方案第一行输出” HelpYou” ,否则输出” ChaoFeng” 。
第二行包括一个数字 m,表示总的操作数。
接下来 m 行,每个两个整数 i, j 含义是进行操作 b[i]^=b[j]
如果有多种可行方案,你只需要输出任意一个。

当时想爆搜的但是T1浪费时间之后T2爆搜和T3爆搜没调好
标算:处理出b的线性基和a的线性基,人工把数列排序,再把b的线性基处理成a的线性基,由异或运算的某个技巧a^=b,b^=a,a^=b可以用来交换a,b然后把a的线性基逆回去就得到了过程.(这个题异或运算的那个技巧还是知道的但是线性基是什么真的不会QAQ)
P.S.奇怪的射命丸文插图好喜感233

//Std by Time-Machine 再次Orz 我爆搜都快比这个长了...
#include<cstdio>
#include<cstdlib>
#include<bitset>
#include<algorithm>
using namespace std;
const int N = 1E5+10;
const int M = 1E6+10;
int n,m,bh[2][N],bit[50];
int on[2],data[N],fuck[N];
int scan(){int i=0;scanf("%d",&i);return i;}
typedef pair<int,int>Data;
typedef bitset<31> Matrix[N];
Matrix mata,matb;
Data out[2][M];
void Swap(int i,int j,int bh[],int &on,Data out[]){
    if(i==j)return;
    //swap(bh[i],bh[j]);
    on++;out[on] = Data(i,j);
    on++;out[on] = Data(j,i);
    on++;out[on] = Data(i,j);
}
int gauss(int n,Matrix a,int bh[],int &on,Data out[]){
    int i,j,top;
    for(i=1,top=30;i<=n&&top>=0;top--,i++){
        int r=i;
        for(j=i;j<=n;j++)
        if(a[j][top]){r=j;break;}
        if(!a[r][top]){i--;continue;}
        swap(a[i],a[r]);
        Swap(i,r,bh,on,out);
        for(j=1;j<=n;j++)
        if(i!=j && a[j][top]){
            a[j] ^= a[i];
            on++;out[on] = Data(j,i);
        }
        bit[i] = top;
    }return i-1;
}
void print(Matrix a){
    int i,j;
    for(i=1;i<=n;i++){
        for(j=10;j>=0;j--)printf("%d ",(int)a[i][j]);
        printf("\n");
    }
}
int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    freopen("copy.in","r",stdin);
    freopen("copy.out","w",stdout);
    int i,j,a,b;
    n = scan();
    for(i=1;i<=n;i++){
        mata[i] = scan();
        bh[0][i]=bh[1][i]=i;
        fuck[i] = i;
    }
    for(i=1;i<=n;i++)matb[i]=data[i]=scan();
    int rank[2];
    rank[1] = gauss(n,matb,bh[1],on[1],out[1]);
    //pay attention the order
    rank[0] = gauss(n,mata,bh[0],on[0],out[0]);
    bool ok = 1;
    if(rank[1] > rank[0])ok=0;
    for(i=1;i<=rank[0] && ok;i++){
        for(j=i;j<=rank[0] && ok;j++)
        if(mata[i][bit[j]]!=matb[i][bit[j]]){
            on[0]++;out[0][on[0]] = Data(bh[0][i],bh[0][j]);
            mata[i] ^= mata[j];
        }
        if(mata[i]!=matb[i])ok=0;
    }
    if(ok){
        printf("HelpYou\n");
        printf("%d\n",on[0]+on[1]);
        for(i=1;i<=on[0];i++)printf("%d %d\n",out[0][i].first,out[0][i].second);
        for(i=on[1];i;i--)printf("%d %d\n",out[1][i].first,out[1][i].second);   
    }else printf("ChaoFeng\n");
    return 0;
}

T3 Pie(原题好像是越南的题= =叫什么划分数列)
这竟然是最水的题?麻麻我不相信!
快12点的时候做到这个题当时看到苹果派我就饿了
主要题干:
现在我们用一个长度为 n 的整数数列 a[]表示苹果派每个部分的难吃程度,
请你求出一个最小 m 使得 Yosafire 可以把苹果派分成恰好 k 份,且每份的难吃
度之和不大于 m。

我的思考过程从爆搜→DP→K分查找(谁知道这个奇怪的东西我怎么想出来的)= =
10分爆搜 30分DP(这两个我还是会= -=)
标算①:100分姿势奇怪 二分m+DP而且还需要用数据结构维护
我们用maxn[i]表示到第i块最多可以分为maxn[i]份,同样的有一个minn数组.
这个题有一个奇怪的规律
“打表发现:如果对于答案m,最多分成r份,最少分成l份,那么[l,r]之间的份数都可以分出来”
卧槽还打表我根本想不到QAQ学长们也没给证明= =
更加奇葩的是数据结构维护
Time-Machine学长用树状数组维护了后缀max
faebdc学长用Splay Σ( ° △ °|||)︴
转移方程:f[i]=max(f[j])+1 0≤j<i,且sum[i]-sum[j]≤m
↑说实话我还是有点不太明白怎么搞的不过是大致明白什么意思和转移方程了=- =
标算②:更加看不懂扔网盘里你们自己啃去吧(不要打我QAQ)
用到了布尔向量和数学归纳法什么的…都不会=- =
Pie官方题解

//Std by Time-Machine 看代码比听标算更懂一点...
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N = 15000+100;
const int MAX = 1E9+7;
int n,m;
int data[N],sum[N],list[N];
int scan(){
    char cc=‘ ‘;int re=0,fh=1;
    while(cc==‘ ‘||cc==‘\r‘||cc==‘\n‘||cc==9)cc=getchar();
    if(cc==‘+‘)cc=getchar(),fh=1;
    if(cc==‘-‘)cc=getchar(),fh=-1;
    while(‘0‘<=cc&&cc<=‘9‘){
        re=re*10+cc-‘0‘;
        cc=getchar();
    }return re*fh;
}

int tree[2][N];
void clear(){for(int i=1;i<=list[0];i++)tree[0][i]=MAX,tree[1][i]=-MAX;}
void push(int x,int val0,int val1){for(;x;x-=x&-x)tree[0][x] = min(tree[0][x],val0),tree[1][x] = max(tree[1][x],val1);}
void get(int x,int &Min,int &Max){int re[2]={+MAX,-MAX};for(;x<=list[0];x+=x&-x)
re[0] = min(tree[0][x],re[0]),re[1] = max(tree[1][x],re[1]);Min=re[0];Max=re[1];}
//int get1(int x){int re=-MAX;for(;x<=list[0];x+=x&-x)re = max(tree[1][x],re);return re;}
bool check(int M){
    clear();
    int tmp,f[2],i;
    tmp = lower_bound(list+1,list+1+list[0],0)-list;
    push(tmp,0,0);
    for(i=1;i<=n;i++){
        tmp = sum[i] - M;
        tmp = lower_bound(list+1,list+1+list[0],tmp) - list;
        get(tmp,f[0],f[1]);
        f[0]++;f[1]++;
        tmp = lower_bound(list+1,list+1+list[0],sum[i]) - list;
        push(tmp,f[0],f[1]);
    }
    return f[0]<=m&&m<=f[1];
}
int main(){
    int i,j;
    freopen("pie.in","r",stdin);
    freopen("pie.out","w",stdout);
    n = scan();m = scan();
    int l,r,help;
    l = r = 0;
    for(i=1;i<=n;i++){
        data[i] = scan();
        sum[i] = sum[i-1] + data[i];
        list[++list[0]] = sum[i];
        if(data[i]>0)r += data[i];
        else l += data[i];
    }
    list[++list[0]] = 0;
    sort(list+1,list+1+list[0]);
    list[0] = unique(list+1,list+1+list[0])-list-1;
    if(l < 0)help = -l;
    else help = 0;
    l += help;r += help;
    while(l<r){
        int mid = (l+r)/2;
        if(check(mid-help))r = mid;
        else l = mid+1;
    }
    printf("%d\n",l-help);
    return 0;
}

第一天就爆零了后面那几天还怎么活啊QAQ
就不能下手轻一点吗QAQ
XPD神犇出的题好歹还搞到了60分呢QAQ
明天还得继续被虐QAQ

【学长虐学弟欢乐赛系列】Round1

标签:省选模拟赛

原文地址:http://blog.csdn.net/creationaugust/article/details/43987161

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