8.7 Round 1

今天思维性差了一点,但是我的失误变得贼多...

T1:https://www.luogu.org/problem/T92371

失误:我 竟然 没看见 多组数据

爆零彻底

找规律题,答案是n * phi[n] / 2

证明:

集合{[0,n-1]中存在逆元的数}==集合{[0,n-1]中存在逆元的数的逆元}

gcd(n,i)=gcd(n,n-i);

所以与n互质的数可以关于n/2对称的,也就是相加等于n;

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<climits>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
#define O(x) cout << #x << " " << x << endl;
#define B cout << "breakpoint" << endl;
#define clr(a) memset(a,0,sizeof(a));
typedef int mainint;
#define int long long
inline int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (ans *= 10) += ch - '0';
        ch = getchar();
    }
    return ans * op;
}
int n;
const int maxn = 2e5 + 5;
int p[maxn],cnt;
bool vis[maxn];
void init(int n)
{
    for(int i = 2;i <= n;i++)
    {
        if(!vis[i]) p[++cnt] = i;
        for(int j = 1;j <= cnt && i * p[j] <= n;j++)
        {
            vis[i * p[j]] = 1;
            if(i % p[j] == 0) break;
        }
    }
}
int gcd(int a,int b) { return !b ? a :gcd(b,a % b); }
mainint main()
{
    freopen("zip.in","r",stdin);
    freopen("zip.out","w",stdout);
    int t = read();
    while(t--)
    {
    int n = read();
    int N = maxn - 5;
    init(N);
    int tot = 1,tp = n;
    for(int i = 2;i <= sqrt(n);i++)
    {
            if(tp % i == 0) tp /= i,tot *= (i - 1);
            while(tp % i == 0) tp /= i,tot *= i;
    }
    if(tp != 1) tot *= (tp - 1);
    printf("%lld
",tot * n / 2);
    }
    return 0;
}
    
         
View Code

T2:https://www.luogu.org/problem/T92372

失误:处理第二问时,我直接向下dfs,这样复杂度会炸

1,3问略

第二问:记录F[u][0]/[1]:u不选/选,除u及其子树以外的点的最小花费

转移:

F[u][0] = F[fa][1] + f[fa] - min(f[u],g[u]);
F[u][1] = min(F[u][0],F[fa][0] + g[fa] - f[u]);

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<climits>
#include<map>
#include<queue>
#include<vector>
using namespace std;
#define O(x) cout << #x << " " << x << endl;
#define B cout << "breakpoint" << endl;
#define clr(a) memset(a,0,sizeof(a));
typedef long long ll;
inline int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (ans *= 10) += ch - '0';
        ch = getchar();
    }
    return ans * op;
}
const int maxn = 1e5 + 5;
const ll mod = 5462617;
int f[maxn],g[maxn],n;
ll cntf[maxn],cntg[maxn];
struct egde
{
    int to,next;
}e[maxn << 1];
int fir[maxn],alloc;
void adde(int u,int v)
{
    e[++alloc].next = fir[u]; fir[u] = alloc; e[alloc].to = v;
    swap(u,v);
    e[++alloc].next = fir[u]; fir[u] = alloc; e[alloc].to = v;
}
void dfs(int u,int fa)
{
    f[u] = 1,g[u] = 0;
    cntf[u] = cntg[u] = 1ll;
    for(int i = fir[u];i;i = e[i].next)
    {
        int v = e[i].to;
        if(v == fa) continue;
        dfs(v,u);
        f[u] += min(f[v],g[v]);
        if(f[v] < g[v]) (cntf[u] *= cntf[v]) %= mod;
        else if(f[v] > g[v]) (cntf[u] *= cntg[v]) %= mod;
        else cntf[u] = cntf[u] * ((cntf[v] + cntg[v]) % mod) % mod;
        g[u] += f[v],(cntg[u] *= cntf[v]) %= mod;
    }
}
bool not_in[maxn];
int F[maxn][2];//0:x不选 1:x选  除x及其子树以外的最大价值 
void deal(int u,int fa)
{
    if(u != 1)
    { 
        F[u][0] = F[fa][1] + f[fa] - min(f[u],g[u]);
        F[u][1] = min(F[u][0],F[fa][0] + g[fa] - f[u]);
    }
    for(int i = fir[u];i;i = e[i].next)
    {
        int v = e[i].to;
        if(v == fa) continue;
        deal(v,u);
    }
}
int main()
{
    freopen("rainbow.in","r",stdin);
    freopen("rainbow.out","w",stdout);
    n = read();
    for(int i = 1;i < n;i++)
    {
        int u = read(),v = read();
        adde(u,v);
    }
    dfs(1,0);
    int ans = min(f[1],g[1]);
    printf("%d
",ans);
    for(int i = 1;i <= n;i++) not_in[i] = 1;
    deal(1,0);
    int cnt = 0;
    for(int i = 1;i <= n;i++) if(F[i][1] + f[i] != ans) cnt++;
    printf("%d
",cnt);
    if(f[1] > g[1]) printf("%lld",cntg[1]); 
    else if(f[1] < g[1]) printf("%lld",cntf[1]);
    else printf("%lld",(cntf[1] + cntg[1]) % mod);
    return 0;
}
/*
5
1 2
1 3
2 4
2 5
*/
View Code

T3:https://www.luogu.org/problem/T92373

失误:二分时存在可能没有LCP的情况,所以要l=0,r = min(len[x],len[y])

二分+哈希

基数记得选>5e5的

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<climits>
#include<map>
#include<queue>
#include<vector>
using namespace std;
#define O(x) cout << #x << " " << x << endl;
#define B cout << "breakpoint" << endl;
#define clr(a) memset(a,0,sizeof(a));
typedef int mainint;
#define int long long
inline int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (ans *= 10) += ch - '0';
        ch = getchar();
    }
    return ans * op;
}
const int mod1 = 1e9 + 7;
const int mod2 = 998244353;
const int b1 = 5e5 + 9;
const int b2 = 5e5 + 29;
const int maxn = 1e5 + 5;
vector<int> hs1[maxn],hs2[maxn];
vector<int> tp[maxn];
int t[maxn * 5],cnt;
int n,m,len[maxn],x,y;
inline bool check(int s)
{
    return hs1[x][s - 1] == hs1[y][s - 1] && hs2[x][s - 1] == hs2[y][s - 1];
}
main()
{
    freopen("girls.in","r",stdin);
    freopen("girls.out","w",stdout);
    n = read(),m = read();
    for(int i = 1;i <= n;i++)
    {
        len[i] = read();
        for(int j = 1;j <= len[i];j++)
        {
            int x = read();
            tp[i].push_back(x);
            t[++cnt] = x;
        }
    }
    sort(t + 1,t + 1 + cnt);
    int tot = unique(t + 1,t + 1 + cnt) - t - 1;
    for(int i = 1;i <= n;i++)
    {
        for(int j = 0;j < len[i];j++)
        {
            tp[i][j] = lower_bound(t + 1,t + 1 + tot,tp[i][j]) - t + 1;
            if(j) hs1[i].push_back((hs1[i][j - 1] * b1 % mod1 + tp[i][j]) % mod1),
                    hs2[i].push_back((hs2[i][j - 1] * b2 % mod2 + tp[i][j]) % mod2);
            else hs1[i].push_back(tp[i][j]),hs2[i].push_back(tp[i][j]);
        }
    }
    while(m--)
    {
        x = read(),y = read();
        int l = 0,r = min(len[x],len[y]);
        bool flag = 0;
        while(l < r)
        {
            int mid = (l + r + 1) >> 1;
            if(check(mid)) l = mid,flag = 1;
            else r = mid - 1;
        }
        printf("%lld
",l);
    }
}
/*
3 3
3 1 2 3
3 1 2 4
5 1 2 3 4 5
1 3
2 1
2 3
*/        
View Code

自以为能够AK结果死的很惨。。。

以后要更小心,看题面,多考虑情况,自以为对的题也要对拍一下

原文地址:https://www.cnblogs.com/LM-LBG/p/11315109.html