2018SD省队集训R2 D1

T1

这里写图片描述

题解

这是个交互QAQ

方法一:找到0的位置(0*x+x=x)为判断条件,然后找到1的位置(1*x+0=x),然后就可以直接递推出剩下的所有数字(1*x+1)。这个算法基本需要3n左右,可以拿到80~100不等(看脸,yzc::rand()了解一下)

方法二:找到0的位置,然后找-1的位置(-1%n=n-1)(-1*x+x=0),然后可以直接找到1的位置,可以推出剩下的数字了

代码

方法一:

int b[5005];
std::vector<int> guess(int n)
{
    vector<int> A;int s0,s1;
    if (n==1) {A.push_back(0);return A;}
    for (int i=0;i<n;i++) b[i]=i;
    srand(20010301);
    random_shuffle(b,b+n);
    for (int i=0;i<n;i++) 
    {
        bool flag=1;
        for (int j=1;j<=50;j++)
          if (query_position(b[i],b[(i+j)%n],b[(i+j)%n])!=b[(i+j)%n]) {flag=0;break;}
        if (flag){s0=b[i];break;}
    }

    for (int i=0;i<n;i++) 
      if (b[i]!=s0)
      {
        bool flag=1;
        for (int j=1;j<=50;j++)
          if (query_position(b[i],b[(i+j)%n],s0)!=b[(i+j)%n]) {flag=0;break;}
        if (flag){s1=b[i];break;}
      }

    for (int i=0;i<n;i++) A.push_back(0);
    A[s0]=0; A[s1]=1; int last=s1;
    for (int i=2;i<n;i++) A[last=query_position(s1,last,s1)]=i;
    return A;
}

T2

这里写图片描述
这里写图片描述

题解

2^n 13pts不说
这里写图片描述
如果离散的话,复杂度是O(n*pre[n])的,可以拿到41pts

代码

41pts

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long 
using namespace std;
const int N=500005;
LL ans=1e18;
int n,a[N],b[N],sb[N];LL f[N][2];
int main()
{
//  freopen("stairs.in","r",stdin);
//  freopen("stairs.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]),sb[i]=a[i];
    sort(sb+1,sb+n+1); int s=unique(sb+1,sb+n+1)-sb-1;
    for (int i=1;i<=n;i++) b[i]=lower_bound(sb+1,sb+s+1,a[i])-sb;
    //f[i][j]表示前i个,第二个序列的最大值是j的最小代价 
    int maxx=0,maid;
    memset(f,0x7f,sizeof(f));
    f[0][0]=0;
    for (int i=1;i<=n;i++) 
    {
        if (maxx<a[i]) maxx=a[i],maid=b[i];
        if (a[i]==maxx) 
        {
            for (int j=0;j<=maid;j++) f[j][i%2]=f[j][(i-1)%2]+a[i];
        }
        else 
        {
            for (int j=b[i];j<=maid;j++) f[j][i%2]=f[j][(i-1)%2]+sb[j]; 
            for (int j=0;j<b[i];j++) f[j][i%2]=f[j][(i-1)%2]+maxx;

            for (int j=0;j<=b[i];j++) f[b[i]][i%2]=min(f[b[i]][i%2],f[j][(i-1)%2]+a[i]);
        }
    }   
    for (int i=0;i<=s;i++) ans=min(ans,f[i][n%2]);
    printf("%lld",ans);
}

T3

这里写图片描述

题解

这道题通过打表找规律可以拿到49pts

代码

#include <cstdio>
#define LL long long 
using namespace std;
const int mod=998244353;
const int N=2005;
int f[N][N],num,jh[N];
int gcd(int a,int b){if (!b) return a;else return gcd(b,a%b);}
LL ksm(LL a,LL k)
{
    LL ans=1;
    for (;k;k>>=1,a=a*a%mod) if (k&1) ans=ans*a%mod;
    return ans;
}
int phi(int n)
{
    int ans=1;
    for (int i=2;i*i<=n;i++)
      if (n%i==0)
      {
        ans*=i-1;n/=i;
        while (n%i==0) n/=i,ans*=i;
      }
    if (n>1) ans*=n-1;
    return ans;
}
LL solve(int n, int k)
{
    if(n == 2) return 1;
    LL ret = ksm(2, n / 2);
    ret = ret * ksm(n, mod - 2) % mod;
    if(k & 1) return ret;
    LL tmp = solve(n / 2, k / 2);
    if(k % 4 == 0) return (ret + tmp) % mod;
    return (ret - tmp + mod) % mod;
}
int main()
{
    freopen("subset.in","r",stdin);
    freopen("subset.out","w",stdout);
    int n,k;scanf("%d%d",&n,&k);
    if (n<=2000)
    {
        for (int i=1;i<=n;i++) if (gcd(n,i)==1) jh[++num]=i;
        f[0][0]=1;
        for (int i=1;i<=num;i++) 
        {
            for (int j=0;j<n;j++) 
              f[i][(j+jh[i])%n]=(f[i][(j+jh[i])%n]+f[i-1][j])%mod;
            for (int j=0;j<n;j++) f[i][j]=(f[i][j]+f[i-1][j])%mod;
        }  
        printf("%d",f[num][k]); return 0;
    }
    if (n%2==1)
    {
        printf("%d",((ksm(2,phi(n))-1+mod)%mod*ksm(n,mod-2)%mod+(k==0))%mod);
        return 0;
    }
    printf("%lld",solve(n,k));
}

猜你喜欢

转载自blog.csdn.net/blue_cuso4/article/details/80876597
今日推荐