Codeforces场合集

Codeforce场合集

Codeforces Round 940 (Div. 2)

1957C 递推

/*
 * @Author     : Danc1ng
 * @Date       : 2024-05-07 13:47:32
 * @FilePath   : 1957C
 * @Origin     : https://codeforces.com/contest/1957/problem/C
 * @Description:
 * @Solution   :
 * 对于n*n的棋盘来说,如果棋子放在(x,x)位置,则剩下方案在(n-1)*(n-1)的棋盘里放置
 * 如果放在(x,y)(x!=y),则剩下方案在(n-2)*(n-2)的棋盘里 考虑递推
 *
 * # # # #
 * # # # #
 * # # @ @
 * # # @ @
 * dp[i]可以由dp[i-1]和dp[i-2]递推过来
 * dp[i-1]递推到dp[i]说明放置在对角线上,只有一种方案-->dp[i]+=dp[i-1]
 * dp[i-2]递推到dp[i]说明放置点不在对角线上,
 * 从dp[i]退化到dp[i-2]是放置在边界的不在对角线上的点,一共(i-2)*2个 -->dp[i]+=(i-1)*dp[i-2]*2;
 * ==>dp[i]=dp[i-1]+(i-1)*dp[i-2]*2;
 *
 */
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;

using namespace std;
typedef pair<int, int> PII;

constexpr int N = 3e5 + 10 , INF = 2e9,mod=1e9+7;

int n,k;
int dp[N];

void init()
{
    dp[0]=dp[1]=1;
    for(int i=2;i<=3e5;i++)
    {
        dp[i]=(dp[i-1]%mod+(i-1)*dp[i-2]%mod*2)%mod;
    }
}


void solve()
{
    cin>>n>>k;
    for(int i=0;i<k;i++)
    {
        int x,y;
        cin>>x>>y;
        if(x==y) n--;
        else n-=2;
    }

    cout<<dp[n]<<endl;
}


signed main()
{
    //freopen("check.in","r",stdin);
    //freopen("check.out","w",stdout);
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);

    init();

    int T;
    //T=1;
    cin>>T;
    while(T--)
    {
      solve();
    }



    return 0;
}

1957D 位运算

/*
 * @Author     : Danc1ng
 * @Date       : 2024-05-07 14:05:21
 * @FilePath   : 1957D
 * @Origin     :
 * @Description:
 * @Solution   :
 * 令s[i]表示1~i的前缀异或和则f(x,z)=s[z]^s[x-1];
 * f(x,y)^f(y,z)>f(x,z)则表示 s[z]^s[x-1]^a[y]>s[z]^s[x-1];
 * 设t=s[z]^s[x-1] ---> t^a[y]>t
 * 对于a[y]中最高位的1来说,如果t对应位为1则t^a[y]变小(即使后面位置改变后为1),
 * 所以要想变大对应位要为0
 * 枚举这个a[y]然后记录方案数
 */
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;

using namespace std;
typedef pair<int, int> PII;

constexpr int N = 2e5 + 10 , INF = 2e9;

int n;
int a[N],s[N];
int c[30][N];

void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        s[i]=s[i-1]^a[i];
        //记录1~i中s[i]该位为1的s[x]的数量
        for(int j=0;j<30;j++)
            c[j][i]=c[j][i-1]+(s[i]>>j&1);
    }

    int ans=0;
    //枚举a[y];
    for(int i=1;i<=n;i++)
    {
        //找a[y]最高位的1
        int k=29;
        while(k>=0&&(a[i]>>k&1)==0) k--;
        if(k==-1) continue;

        /*
        当前a[y]的最高位的1为k,要想t为0则s[z]和s[x-1]的k位要么都为1,要么都为0
        z的范围位[i,n];x-1的范围位[1,i-1]
         */
        ans+=(c[k][n]-c[k][i-1])*c[k][i-1];//i~n中k位为1的s[z]数量*(1~i-1)中k位为1的s[x-1]数量
        ans+=(n-i+1-(c[k][n]-c[k][i-1]))*(i-c[k][i-1]);//总数量减1的数量就是0的数量
    }
    cout<<ans<<endl;
}


signed main()
{
    //freopen("check.in","r",stdin);
    //freopen("check.out","w",stdout);
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    int T;
    //T=1;
    cin>>T;
    while(T--)
    {
      solve();
    }



    return 0;
}

1957E 数学 -威尔逊定理

/*
 * @Author     : Danc1ng
 * @Date       : 2024-05-07 15:00:18
 * @FilePath   : 1957E
 * @Origin     : https://codeforces.com/contest/1957/problem/E
 * @Description:
 * F(i,k)表示从i个数中选k个数的环排列数,给一个n求 Σ(i=1~n)Σ(j=1~i)(F(i,j)mod j)
 * @Solution   :
 *
 * n的环排列数为(n-1)!, n的排列数为n!,而1,2,3,..n和2,3,...,n,1是一个环排列,这样有n个 所以答案为 n!除以n=(n-1)!
 * 那么对于F(i,j) mod j = C(i,j)*(j-1)! mod j= A(i,j)/A(j,j)*(j-1)!mod j=A(i,j)/j mod j;
 * 由于分子是 j 个连续整数的乘积,因此至少有一个整数能被 j 整除
 * i*(i-1)*(i-2)*....*(i-j+1)/j mod j= (j-1)!*(i/j) mod j;
 * 在这里我们可以发现,j的所有适当因数都会出现在 (j−1)! 中,因此根据这一点我们可以知道, C(i,j)mod j =0
 * 适用于除 j=4 之外的所有合数 j
 * 威尔逊定理,我们知道当 j 是质数时,(j−1)! ≡−1 modj
 。
 *
 */
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;

using namespace std;
typedef pair<int, int> PII;

constexpr int N = 1e6 + 10 , INF = 2e9,mod=1e9+7;

int n;
bool notPri[N];
int f[N];


void init()
{
    for(int j=2;j<N;j++)
    {
        if(!notPri[j]||j==4)
        {
            for(int i=j;i<N;i+=j)
            {
                notPri[i]=true;
                int d=i/j*(j==4?2:j-1)%j;
                (f[i]+=d)%=mod;
                if(i+j<N) (f[i+j]+=mod-d)%=mod;
            }
        }
    }

    for(int i=1;i<N;i++) (f[i]+=f[i-1])%=mod;
    for(int i=1;i<N;i++) (f[i]+=f[i-1])%=mod;
}

void solve()
{
    cin>>n;
    cout<<f[n]<<endl;

}


signed main()
{
    //freopen("check.in","r",stdin);
    //freopen("check.out","w",stdout);
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);


    init();

    int T;
    cin>>T;
    while(T--)
    {
        solve();
    }



    return 0;
}

Codeforces Round 941 (Div. 2)

1966D 构造

/*
 * @Author     : Danc1ng
 * @Date       : 2024-05-08 22:52:28
 * @FilePath   : 1966D
 * @Origin     : https://codeforces.com/contest/1966/problem/D
 * @Description: 构造出一个长度不超过25的序列使子序列可以表示1~n中除k以外所有的数
 * @Solution   :
 * 首先考虑如何表示1~n中所有数,用1,2,4,8,16...二进制即可
 * 为了不表示k则我们可以对于1~k-1的数用1,2,4,8,16...来表示,
 * 假设k的最高位为h,则将2^h替换为(k-1)-Σ(2^i)(0<=i<=h-1),则前h+1项可以表示出[1,k-1],
 * 加入k+1,则可以表示[1,2k],再加入2k则可以表示[1,4k],再加入4k则可以表示[1,8k],...
 * 但因为k不能表示所以3k无法表示
 */
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;

using namespace std;
typedef pair<int, int> PII;

constexpr int N = 2e5 + 10 , INF = 2e9;

int n,k;
int a[N];


void solve()
{
    cin>>n>>k;
    int len=0,k1=k;

    vector<int> ans;
    if(k==1)
    {
        ans.push_back(3);
        for(int i=1;i<=24;i++) ans.push_back(1<<i);
    }
    else
    {
        while(k1)
        {
            k1>>=1;
            len++;
        }
        int res=1;
        for(int i=1;i<len;i++)
        {
            ans.push_back(res);
            res*=2;
        }
        ans.push_back(k-(1<<(len-1)));
        ans.push_back(k+1);
        ans.push_back(3*k);
        res=2;
        while(ans.size()<25)
        {
            ans.push_back(res*k);
            res*=2;
        }
    }

    cout<<25<<endl;
    for(auto i:ans) cout<<i<<' ';
    cout<<endl;

}


signed main()
{
    //freopen("check.in","r",stdin);
    //freopen("check.out","w",stdout);
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    int T;
    //T=1;
    cin>>T;
    while(T--)
    {
      solve();
    }



    return 0;
}

Educational Codeforces Round 165 (Rated for Div. 2)

1969C DP

/*
 * @Author     : Danc1ng
 * @Date       : 2024-05-09 16:01:49
 * @FilePath   : 1969C
 * @Origin     : https://codeforces.com/contest/1969/problem/C
 * @Description:
 * 给一个长度为n的数组,每个可以选择数组的一个元素用它相邻的元素替代它,最多可以进行k次操作
 * 问数组和的最小值是多少
 * @Solution   :
 *
 * 直接每次操作找差值最大的位置的思路是错误的,因为最小值传递后差值可能会更大更优
 * 例如n=6,k=3, 4 1 2 4 4 3 --> 1 1 1 1 4 3 !-->1 1 1 2 4 3
 * 因为k比较小 考虑dp
 * dp[i][j]表示到i的时候用了j次操作的最小和
 * dp[i][j]=min(dp[i-1][j]+a[i](不操作),dp[i-k-1][j-k]+min(a[i-k],a[i-k+1],...,a[i]))操作k次
 */
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;

using namespace std;
typedef pair<int, int> PII;

constexpr int N = 3e5 + 10 , INF = 1e18;

int n,k;
int a[N];

void solve()
{
    cin>>n>>k;

    vector<vector<int>> dp(n+1,vector<int>(k+1,INF));

    dp[0][0]=0;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        dp[i][0]=dp[i-1][0]+a[i];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=k;j++)
        {
            int res=a[i];
            //该位置不操作
            dp[i][j]=min(dp[i][j],dp[i-1][j]+res);
            //枚举操作次数1~j
            for(int l=1;l<=j&&l+1<=i;l++)
            {
                res=min(res,a[i-l]);
                dp[i][j]=min(dp[i][j],dp[i-l-1][j-l]+(l+1)*res);
            }
        }
    }

    cout<<*min_element(dp[n].begin(),dp[n].end())<<endl;

}


signed main()
{
    //freopen("check.in","r",stdin);
    //freopen("check.out","w",stdout);
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    int T;
    //T=1;
    cin>>T;
    while(T--)
    {
      solve();
    }



    return 0;
}

1969D 贪心

/*
 * @Author     : Danc1ng
 * @Date       : 2024-05-09 19:14:13
 * @FilePath   : 1969D
 * @Origin     : https://codeforces.com/contest/1969/problem/D
 * @Description:
 * 有n件商品,ai是alice购买i商品需要的价格,bi是bob购买i商品需要的价格
 * alice选若干个商品,若商品数量<k则bob免费拿走所有商品,否则bob拿免费拿走alice购买的商品中k件
 * 其他付费购买,alice的利润是bob购买的商品价格之和-alice购买的商品价格之和,alice希望利润最大化
 * bob希望alice的利润最小化,求都采取最优行动下的alice的利润
 * @Solution   :
 * 假设现在alice购买了若干物品那么bob会选择免费拿去价格大的前k个,
 * 那么以bi升序排列,找一个分界点,则右侧有bob的免费的k个物品,
 * 对于bob拿的免费的物品,alice一定是亏的,alice选择ai最小的k个则会亏得最少
 * 对于分界点的左侧,只要bi>ai则有利润,直接购买
 */
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;

using namespace std;
typedef pair<int, int> PII;

constexpr int N = 2e5 + 10 , INF = 2e9;

struct Node
{
    int x,y;
}a[N];

int n,k;
int pre[N];

bool cmp(Node a,Node b)
{
    return a.y<b.y;
}

void solve()
{
    cin>>n>>k;

    for(int i=1;i<=n;i++)
    {
        cin>>a[i].x;
    }
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].y;
    }

    sort(a+1,a+n+1,cmp);


    for(int i=1;i<=n;i++)
    {
        pre[i]=pre[i-1]+max(0ll,a[i].y-a[i].x);
    }

    priority_queue<int> q;
    int ans=0,sum=0;
    for(int i=n;i>=1;i--)
    {
        if(q.size()>=k)
        {
            ans=max(ans,pre[i]-sum);
        }
        q.push(a[i].x);
        sum+=a[i].x;
        if(q.size()>k)
        {
            sum-=q.top();
            q.pop();
        }
    }

    cout<<ans<<endl;


}


signed main()
{
    //freopen("check.in","r",stdin);
    //freopen("check.out","w",stdout);
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    int T;
    //T=1;
    cin>>T;
    while(T--)
    {
      solve();
    }



    return 0;
}

Codeforces Round 942 (Div. 2)

1972B- 博弈 找性质

/*
 * @Author     : Danc1ng
 * @Date       : 2024-05-10 15:37:55
 * @FilePath   : 1972B
 * @Origin     : https://codeforces.com/contest/1972/problem/B
 * @Description:
 * @Solution   :
 * 对于UUU,DUD,UUD,DUU四种情况来说,操作后U的数量改变为-3,+1,-1,-1,也就是说操作后U的数量的奇偶性会改变
 * 因为最终面临U为0的时候会败,所以如果先手U的数量为奇数则会赢,因为操作后总会把U为偶数的局面留给后手,
 * 而先手U的数量为偶数则会败,因为后手总会把U为偶数的局面留给自己
 */
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;

using namespace std;
typedef pair<int, int> PII;

constexpr int N = 2e5 + 10 , INF = 2e9;

int n;
int a[N];
char c[N];

void solve()
{
    cin>>n;
    int cnt=0;
    for(int i=0;i<n;i++)
    {
        cin>>c[i];
        if(c[i]=='U') cnt++;
    }
    if(cnt&1) YES
    else NO
}


signed main()
{
    //freopen("check.in","r",stdin);
    //freopen("check.out","w",stdout);
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    int T;
    //T=1;
    cin>>T;
    while(T--)
    {
      solve();
    }



    return 0;
}

1972C-构造 二分

/*
 * @Author     : Danc1ng
 * @Date       : 2024-05-10 19:41:25
 * @FilePath   : 1969C
 * @Origin     : https://codeforces.com/contest/1972/problem/C
 * @Description:
 * 给一个长度为n的数组a,a[i]表示数字为i的牌有a[i]个,你可以再购买k张任意数字的牌,
 * 然后给牌重新排列,重新排列的分数是长度为n的连续子数组中的全排列个数,最高得分是多少
 * @Solution   :
 * 要解决 1.如何购买k张牌,2.如何排列
 * 优先购买牌数少的数字的牌,由于k<=10^12,所以需要一次性知道最终最少的牌的数量,可以二分答案
 * 如何排列, 像1 2 3 1 2 3 1 2 3--1 2 这样能最大化得分,假设1 2 各多一张,则可以放在后面
 * 也就是说优先放牌数多的然后放牌数少的 再放多余的牌
 * 答案就是1+(mi-1)*n+多出来的牌数 mi表示购买k张后最少的牌的数量
 */
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;

using namespace std;
typedef pair<int, int> PII;

constexpr int N = 2e5 + 10 , INF = 2e9;

int n,k;
int a[N];

bool check(int mid)
{
    int need=0;
    for(int i=1;i<=n;i++)
        if(a[i]<mid) need+=mid-a[i];

    return need<=k;
}

void solve()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];

    int l=1,r=2e12;
    while(l<r)
    {
        int mid=(l+r+1)>>1;
        if(check(mid)) l=mid;
        else r=mid-1;
    }

    int mi=r;
    for(int i=1;i<=n;i++)
    {
        if(a[i]<mi)
        {
            k-=mi-a[i];
            a[i]=mi;
        }
    }
    int num=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==mi&&k) a[i]++,k--;
        if(a[i]>mi) num++;
    }

    cout<<1+(mi-1)*n+num<<endl;
}


signed main()
{
    //freopen("check.in","r",stdin);
    //freopen("check.out","w",stdout);
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    int T;
    //T=1;
    cin>>T;
    while(T--)
    {
      solve();
    }



    return 0;
}

1972D1-数学

/*
 * @Author     : Danc1ng
 * @Date       : 2024-05-10 20:54:08
 * @FilePath   : 1972D1
 * @Origin     : https://codeforces.com/contest/1972/problem/D1
 * @Description:
 * 给两个正整数n,m,求满足a+b是b*gcd(a,b)的倍数的(a,b)的个数 (1<=a<=n,1<=b<=m);
 * @Solution   :
 *
 * gcd(a,b)*b|a+b => k*b*gcd(a,b)=a+b => k*gcd(a,b)=a/b+1 因为gcd(a,b)和k都是整数,
 * 所以a/b+1 为整数 => a/b为整数 => b|a => b * b | a + b
 * kb+b是b^2的倍数,即k+1是b的倍数,因为a+b<=n+b,所以k+1<=n+b/b,
 * 那么当前的贡献就是k+1/b==n+b/(b^2),枚举b即可
 */
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;

using namespace std;
typedef pair<int, int> PII;

constexpr int N = 2e5 + 10 , INF = 2e9;

int n,m;


void solve()
{
    cin>>n>>m;
    int ans=0;
    for(int i=1;i<=m;i++)
    {
        ans+=(n+i)/(i*i);
        if(i==1) ans--;//b=1 时贡献为n
    }

    cout<<ans<<endl;
}


signed main()
{
    //freopen("check.in","r",stdin);
    //freopen("check.out","w",stdout);
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    int T;
    //T=1;
    cin>>T;
    while(T--)
    {
      solve();
    }



    return 0;
}

1972D2- 数学

/*
 * @Author     : Danc1ng
 * @Date       : 2024-05-10 20:54:18
 * @FilePath   : 1972D2
 * @Origin     :
 * @Description:
 * 给两个正整数n,m,求满足b*gcd(a,b)是a+b的倍数的(a,b)的个数 (1<=a<=n,1<=b<=m);
 * @Solution   :
 * 当gcd(a,b) == 1时,a+b|b 不成立
 * 当gcd(a,b) != 1时,设gcd(a,b)==g, a=g*ka,b=g*kb, b*g是g(ka+kb)的倍数,b是ka+kb的倍数
 * g*kb 是ka+kb的倍数,所以g是ka+kb的倍数,枚举gcd(ka,kb) == 1的所有(ka,kb)  在看g为ka+kb的倍数情况
 * 但是O(n*m)的复杂度,  所以要缩小ka和kb的枚举范围, g是ka+kb的倍数,所以g>ka,ka*ka<g*ka=a<=n,
 * 所以ka<=sqrt(n),同理kb<=sqrt(m);
 *
 * 因为a=g*ka<=n,b=g*kb<=m,所以g最大可以是min(n/ka,m/kb) 
 */
#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;

using namespace std;
typedef pair<int, int> PII;

constexpr int N = 2e5 + 10 , INF = 2e9;

int n,m;


void solve()
{
    cin>>n>>m;
    int ans=0;
    for(int i=1;i<=sqrt(n);i++)
    {
        for(int j=1;j<=sqrt(m);j++)
        {
            if(__gcd(i,j)==1)
            {
                int k=min(n/i,m/j);
                ans+=k/(i+j);
            }
        }
    }
    cout<<ans<<endl;
}


signed main()
{
    //freopen("check.in","r",stdin);
    //freopen("check.out","w",stdout);
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    int T;
    //T=1;
    cin>>T;
    while(T--)
    {
      solve();
    }



    return 0;
}
posted @ 2024-05-10 00:04  Danc1ng  阅读(38)  评论(0)    收藏  举报