B Binary Vector

链接:https://ac.nowcoder.com/acm/contest/5671/B
题意
给定一串数列f,可以找出他们的规律f[i]=f[i-1](2^i-1)/2^i.求f[1]^....f[n]异或和
题解
由小费马引理可知:a/b%mod=ab^(mod-2)%mod;令初值1/2%mod=q;每次只需要再原来的f[i-1]之上q
(2^i-1);打表把所有的f[i]求出来
注意
%mod
代码

#include<bits/stdc++.h>
const int mod=1e9+7;
const int maxn=2e7+10;
using namespace std;
typedef long long ll;

ll quick_pow(ll a, ll b) {
    ll ans = 1;
    while (b) {
        if (b & 1) ans = (ans * a) % mod;
        b >>= 1;
        a = (a * a) % mod;
    }
    return ans % mod;
}
ll ans[maxn];
int main()
{
    //费马小定理:a/b%p=a*b^(p-2)     第一次操作时,p=1,q=2^(mod-2) ,之后q=4^(mod-2)  8^(mod-2),
    ll p=1,q=quick_pow(2,mod-2),now=2,inv=q,ori=q;
    //printf("%lld",q);

    for(int i=1;i<=2e7;i++)
    {
        ans[i]=(p*q)%mod;//直接放进去一起计算了
        now=(now*2)%mod;//now-1   ->1 3      2, 4
        p=(p*(now-1))%mod;
        inv=(inv*ori)%mod;
        q=(q*inv)%mod;//有直接乘以之前的ans[i-1];
    }//求得就是每一个f[i]
    for(int i=2;i<=2e7;i++)ans[i]^=ans[i-1];
    int t;
    scanf("%d",&t);
    while (t--)
    {
        int n;
        scanf("%d",&n);

        printf("%lld\n",ans[n]);
    }
    return 0;
}

C Combination of Physics and Maths

链接:https://ac.nowcoder.com/acm/contest/5671/C
题意
给定一个矩阵,框中一个区域,可以删去行或者列,构成一个新的矩阵,求这样的矩阵的和加起来x,除以最下面一行的所有和y,x/y的值最大为多少
题解
a/b c/d max(a/b,c/d)>a+b/c+d即求出某一列列里面的前缀和/最后一行的数最大的值
注意
不仅可以删除列,还可以删除行,当然是从后往前删
代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
double matr[210][210];
double line[210][210];
double cha[210][210];

int main() {
    int T, n, m;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &m);
        double maxn = 0.0;
        memset(matr, 0.0, sizeof(matr));
        memset(line, 0.0, sizeof(line));
        memset(cha, 0.0, sizeof(cha));
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                scanf("%lf", &matr[i][j]);
                line[i][j] = line[i - 1][j] + matr[i][j];
            }
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                cha[i][j] = line[i][j] * 1.0 / matr[i][j];
            }

            sort(cha[i] + 1, cha[i] + m+1);
            if (maxn < cha[i][m])maxn = cha[i][m];
        }
        /*for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                printf("%.2lf ", cha[i][j]);
            }
            printf("\n");
        }*/
        printf("%.8lf\n", maxn);
    }
    return 0;
}

K K-Bag

链接:https://ac.nowcoder.com/acm/contest/5671/K
题意
定义k-bag:1~ k不重复的随机排列,这样有无数个排列连在一起构成一个合理的排列,给定一个一定的字符串,问是否是这个排列的子序列
题解
先离散化一下,把字符串中所有出现的数字,整合一下,重新表示。再遍历每一个对应的编号,在每两个相同的相邻编号之间,用数组d[k]的形式来表示i%k,和之前编号c[a[i]]%k在他们的区间内,用前缀和表示,左加右减,若出现后面的编号%k>前面编号%k,那么就是在前面编号%k~ k,0~ 后面编号%k,表示连续。这些的前缀和==进入这个循环的个数,则他们都好好的待在自己的序列里头
注意
左加右减,在相同的编号上,这样后面那个编号不计入这次的循环中,而是在下一个循环中大显身手。详情看看代码吧,我太low了。
代码

#include<bits/stdc++.h>
using namespace std;
#define maxn 500005
int a[maxn],b[maxn],c[maxn],d[maxn],ans,sum,cnt,n,t,k;
int main()
{
    for(scanf("%d",&t);t--;)
    {
        memset(a,0,sizeof(a));memset(b,0,sizeof(b));memset(c,0,sizeof(c));memset(d,0,sizeof(d));
        bool flag=1;cnt=0;d[0]=0;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if(a[i]>k)flag=0;
            b[i]=a[i];
            c[i]=d[i]=0;//初始化
        }
        if(!flag){
            printf("NO\n");continue;
        }
        sort(b+1,b+n+1);
        sum=unique(b+1,b+n+1)-b-1;// 这个unique函数在sort排序后,进行一个去重,会把不重复的都放在前面给替换掉,而剩下的数不进行改变
        // 实际上这个sum就相当于不重复的数的个数
        for(int i=1;i<=n;i++)
        {
            a[i]=lower_bound(b+1,b+1+sum,a[i])-b;//位置,第一个等于a[i]的位置
            //这个步骤就是把一些可能断着的数字放在一起来统计了
        }
        for(int i=1;i<=n;i++)
        {
            if(c[a[i]]&&i-c[a[i]]<k)//表示之前的那个相同的数和它距离小于k,如果大于k就不用进行判定了,直接成立然后末尾更新
            {
                d[c[a[i]]%k]++;//左端点+1
                cnt++;//统计所有进入这个循环的个数
                if(c[a[i]]%k<i%k)d[i%k]--;//右端点-1
                else d[min(k,n-1)]--,d[0]++,d[i%k]--;//以两个数之间为一个区间加上去。
            }
            c[a[i]]=i;//i表示的是这个数真正的顺序

        }
        if(d[0]==cnt){printf("YES\n");continue;}
        else
        {
            for(int i=1;i<=n;i++)
            {
                d[i]+=d[i-1];
                if(d[i]==cnt){printf("YES\n");flag=0;break;}
            }
        }
        if(flag)printf("NO\n");

    }
    return 0;

}