A题
题意:问能否找出一个子序列使得其积不是完全平方数
解:只要找到一个不是完全平方的元素就可以找到这样的子序列

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        double eps = 1e-5;
        int t = sc.nextInt();
        while(t-- != 0) {
            int n = sc.nextInt();
            boolean f = false;
            while(n-- != 0) {
                int x = sc.nextInt();
                if(Math.abs((int)Math.sqrt(x) * (int)Math.sqrt(x) - x) < eps) continue;
                //System.out.println("asdlfjs");
                f = true;
            }
            if(f) System.out.println("YES");
            else System.out.println("NO");
        }
    }
}

B题
题意:问有多少个长度为n的数组满足:
所有元素都在0~(2^k)-1,所有元素and的值为0,元素的和尽可能大
解:n个数中,每个数字二进制下都有k位,对于每一位,和尽可能大且and值为0的操作是有一个数字的这一位是0,其余都是1。答案是n^k

import java.util.Scanner;

public class Main {

    final static long p = (long)1e9 + 7;

    public static long ksm(long a,long b) {
        long s = 1;
        while(b != 0) {
            if((b & 1) != 0) s = s * a % p;
            a = a * a % p;
            b >>= 1;
        }
        return s % p;
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        while(t-- != 0) {
            long x = sc.nextLong();
            long y = sc.nextLong();
            System.out.println(ksm(x,y));
        }
    }
}

C题
题意:给出n,从[1,2,3...n-1]中找出最长的子序列,使其乘机x%n = 1
解:首先,假定我们选择的序列包含数a,设其他数的乘积为x(mod n),那么就有a∗x≡1(modn),也就是x是a的逆元。那么a就要满足gcd(a,n)=1,否则a没有逆元,不可能入选
把所有与n互质的数在模n意义下乘起来,可以得到一个小于n的数ans,ans一定与n互质。那么ans一定在前面出现过,如果ans≠1,那么在答案序列中把那个数删掉就行了。
假设出了ans以外,其他数的乘积为y,那么就有ans ∗ y mod n = ans,得到y mod n=1。

import java.util.Scanner;

public class Main {

    public static int gcd(int a,int b) {
        if(b == 0) return a;
        return gcd(b,a % b);
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = 1;
        int[] a = new int[100010];
        int n = sc.nextInt();
        long ans = 1;
        for(int i = 1;i <= n; ++i)
            if(gcd(i,n) == 1) {
                a[t++] = i;
                ans = ans * i % n;
            }
        if(ans != 1) {
            boolean f = false;
            System.out.println(t - 2);
            for(int i = 1;i < t; ++i) {
                if(a[i] == ans) continue;
                if(f == true) System.out.print(" ");
                f = true;
                System.out.print(a[i]);
            }
            System.out.println();
        }
        else {
            System.out.println(t - 1);
            for(int i = 1;i < t; ++i)
                System.out.print(a[i] + ((i == t - 1)?"\n":" "));
        }
    }
}

D题
题意:长度为n的数组和q个询问,每次询问区间[l,r]里的数最少要分成几组才能使每组内出现次数最多的都不超过(n/2向上取整)
解:
可以用vector记录每个数出现的位置,然后二分找出在某个区间内出现的次数。
怎样知道在这个区间内哪个数的出现次数最多呢?
线段树维护
假设区间有x个数,出现次数最多的数字出现了f次
f <= (x/2向上取整) 1
f > (x/2向上取整) 剩下的x-f最多可以与x-f+1个数合成一组,剩下的每个数都自己一组,那么就是f-(x-f+1) + 1 = 2*f-x

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

const int maxn = 3e5 + 10;
#define lt(x) x << 1
#define rt(x) x << 1 | 1
int n,q,s,e;
vector<int>v[maxn];
int a[maxn],t[maxn * 4];

int getnum(int l,int r,int x)
{
    return upper_bound(v[x].begin(),v[x].end(),r) - lower_bound(v[x].begin(),v[x].end(),l);
}

int mymax(int x,int y,int l,int r)
{
    int t1 = getnum(l,r,x),t2 = getnum(l,r,y);
    if(t1 > t2) return x;
    return y;
}

void build(int x,int l,int r)
{
    if(l == r)
    {
        t[x] = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(lt(x),l,mid);
    build(rt(x),mid + 1,r);
    t[x] = mymax(t[lt(x)],t[rt(x)],l,r);
}

int query(int x,int l,int r)
{
    if(s <= l && r <= e) return getnum(s,e,t[x]);
    int mid = (l + r) >> 1;
    int t1 = 0,t2 = 0;
    if(s <= mid) t1 = query(lt(x),l,mid);
    if(e > mid) t2 = query(rt(x),mid + 1,r);
   // cout<<t1<<' '<<t2<<endl;
    return max(t1,t2);
}

int main()
{
    std::ios::sync_with_stdio(false);
    cin>>n>>q;
    for(int i = 1;i <= n; ++i)
    {
        cin>>a[i];
        v[a[i]].push_back(i);
    }
    build(1,1,n);
    while(q--)
    {
        cin>>s>>e;
        cout<<max(1,2 * query(1,1,n) - (e - s + 1))<<'\n';
    }
    return 0;
}