2018 hdu 多校 3

被claris教育了……
补题进度[5/13] 场上3题

Problem D. Euler Function
题意就是找到第k小的欧拉函数为合数的数
其实打个表就能看出来,从8开始的欧拉函数就是合数了,直接输出就行

Problem F. Grab The Tree
题意是两个人从树上任意选点,先手只能选不在一条边上的点,后手拿走剩下的点。最后选的点的异或和最大谁胜出。否则平局。

场上我是这样考虑的,如果有必胜点,那么无论如何先手都可以选择这个点。其实我们只要看最高位的个数,假设含有最高位的数的个数有奇数个,只要我选择一个就行,剩下的点就被异或掉了,假如有偶数个,那我选择次高位上的……总之最后能得出一个结论就是,先手一定会胜出。
那么平局呢?如果先手一个都不选,但是所有的点的异或和恰好是0,这样不管则么选,都只有平局和输两种可能性,所以只要判断下异或和是不是0就i行。

#include 
#include 
#include 
#include 
#include 
#define ull unsigned long long
using namespace std;
const int maxn = 1e5 + 5;
vector<int> edge[maxn];
int w[maxn];
int son[maxn];
int dp[maxn][2];
void dfs(int u,int p)
{
    dp[u][1] = w[u];
    dp[u][0] = 0;
    for(auto v : edge[u])
    {
        if(v == p) continue;
        dfs(v,u);
        son[u] = v;
        dp[u][1] = max(dp[son[v]][1]^w[u],dp[u][1]);
        dp[u][0] = max(dp[v][1],dp[u][0]);
    }
}
int main()
{
    int ca,n;
    scanf("%d", & ca);
    while(ca--)
    {
        scanf("%d",&n);
        int x,y,z = 0;
        for(int i = 0;iscanf("%d",&w[i]);
            z ^= w[i];
        }
        for(int i = 0;i1;i++)
        {
            scanf("%d%d", &x,&y);
        }
        if(z == 0) printf("D\n");
        else printf("Q\n");

    }
    return 0;
}

ps:装模做样的读入了所有的数据……

Problem L. Visual Cube
这道题是模拟,直接模拟就行了

Problem A. Ascending Rating
这道题的题意就是给出一个数列,求出长度为m的子序列中最大值和更新最大值的次数。
暴力的方法肯定是T,那么我们可以倒着考虑,用单调队列维护窗口最大值的方法就可以得出区间最大值,此时的单调队列大小就是更新的次数。
为什么队列长度是更新的次数呢?首先答案肯定是更新的方向是没有关系的,那么在更新的时候,每次队列中留下来的都是在相关区间的有序长度,也就是我们想说的变化次数。

#include 
using namespace std;
#define INF 1000000007
#define ll long long
const int maxn = 1e7 + 7;
ll a[maxn];
int main()
{
    int n,m,k,p,q,r,mod;
    int ca;
    scanf("%d", &ca);
    while(ca--)
    {
        scanf("%d%d%d%d%d%d%d",&n,&m,&k,&p,&q,&r,&mod);
        for(int i = 1;i<=k;i++)
        {
            scanf("%lld", &a[i]);
        }
        for(int i = k+1;i <= n;i++)
        {
            a[i] = (p * a[i-1] + (ll)q*i +r) % (ll)mod;
        }
        deque<int> Q;
        ll A = 0,B = 0;
        for(int i = n;i;i--)
        {
            while(!Q.empty() && a[Q.back()] <= a[i]) Q.pop_back();
            Q.push_back(i);
            if(i +m-1<= n)
            {
                while(Q.front() >= i + m) Q.pop_front();
                A += a[Q.front()] ^ i*1LL;
                B += i*1LL ^ (ll)Q.size();
               // cout<
              //  cout<
            }
        }
        printf("%lld %lld\n",A,B);

    }

    return 0;
}

/*
2
12 1
2
24 1
2
35 8
1
40 9
1
46 11
46 11
*/

Problem C. Dynamic Graph Matching
题意:有两种操作,一次操作添加一条边,或者删除一条边。输出每次匹配数为1,2,3,…,n/2的匹配的个数。
解法我学习了 claris 的题解,下面谈谈我自己的理解。首先我们用DP来求解,因为只有10个点。 F[i][S] F [ i ] [ S ] 代表第i次操作,当前状态为S(每个点取或者不取,雅索状态),那么加一条边相当于 F[i][S]=F[i1][Suv]+F[i1][S]) F [ i ] [ S ] = F [ i − 1 ] [ S − u v ] + F [ i − 1 ] [ S ] )
其实我们只要将所有的状态从大到小更新一下,大的状态在小状态计算之前就已经计算了。就能将加入一条边的操作变成: F[S]+=F[Suv] F [ S ] + = F [ S − u v ]
由于题目中保证了删边的合法性,那么什么时候加入这条边对最后的结果不产生影响了。所以我们直接把加边操作反过来写,从小到大进行操作。

#include 
using namespace std;
#define INF 1000000007
#define ll long long
const int maxn = 1<<11;
const int mod = 1e9 + 7;
inline void add(int&a,int b)
{
    a=a+bsub(int&a,int b)
{
    a=a-b>=0?a-b:a-b+mod;
}
int f[2024];
int cnt[2024];
int ans[2024];
int tot;
int main()
{
    int ca;
    scanf("%d",&ca);
    while(ca--)
    {
        int n,m;
        scanf("%d%d", &n,&m);
        tot = 1<for(int i = 0; i0;
            cnt[i] = __builtin_popcount(i);
        }
        f[0] = 1;
        while(m--)
        {
            char op[10];
            int u,v;
            scanf("%s%d%d",op,&u,&v);
            u--,v--;
            int s = (1<1<if(op[0] == '+')
            {
                for(int i = tot-1 ; ~i; i--)
                {
                    if(!(i & s))
                        add(f[i^s],f[i]);
                }
            }
            else
            {
                for(int i = 0; iif(!(i & s))
                        sub(f[i^s],f[i]);
                }
            }
            for(int i = 1; i<=n; i++) ans[i] = 0;
            for(int i = 1; ifor(int i = 2; i<=n; i+= 2)
            {
                printf("%d%c",ans[i],i < n ? ' ' : '\n' );
            }
        }


    }
    return 0;
}

/*
1
4 8
+ 1 2
+ 3 4
+ 1 3
+ 2 4
- 1 2
- 3 4
+ 1 2
+ 3 4
*/

你可能感兴趣的:(2018多校题解)