Educational Codeforces Round 84 (Rated for Div. 2) Mar/23/2020 22:35UTC+8

比赛链接 https://codeforces.com/contest/1327
比赛记录 https://blog.csdn.net/cheng__yu_/article/details/105395197

A. Sum of Odd Integers

在这里插入图片描述
思路: n ≥ ( 1 + 2 k − 1 ) × k 2 = s u m n\ge \frac {(1+2k-1)\times k} 2=sum n2(1+2k1)×k=sum,且n与sum奇偶性相同,则yes

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

int main()
{
	int t,n,k;
	cin>>t;
	while(t--)
	{
		cin>>n>>k;
		int t=2*k-1;
		ll sum=1ll*(1+t)*k/2;
		if(n<sum)
		{
			cout<<"NO\n";
			continue;
		}
		if(!(n-sum&1))
			cout<<"YES\n";
		else
			cout<<"NO\n";		
	}
	return 0;
}

B. Princesses and Princes

在这里插入图片描述
题意:n个公主n个王子,每个公主有一个选择的列表,每次从列表第一个开始匹配未匹配的王子,问最后能否完全匹配完,没匹配完的话,输出一对未匹配的公主和王子的编号
思路:拿 set 记录一下,然后不断删去已经匹配的

#include <bits/stdc++.h>
#define ll long long 
using namespace std;
int t,n,k;
set<int> s1,s2;

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		s1.clear(),s2.clear();
		for(int i=1;i<=n;++i)	
			s1.insert(i),s2.insert(i);
		for(int i=1;i<=n;++i)
		{
			scanf("%d",&k);
			for(int j=1;j<=k;++j)
			{
				int x;
				scanf("%d",&x);
				if(s2.count(x)&&s1.count(i))
				{
					s1.erase(i),s2.erase(x);
				}	
			}
		}
		if(!s1.empty())
		{
			printf("IMPROVE\n");
			printf("%d %d\n",*s1.begin(),*s2.begin());
		}
		else
			printf("OPTIMAL\n");
	}
	return 0;
}

C. Game with Chips

在这里插入图片描述
题意 n × m n\times m n×m 的棋盘上,有k个棋子需要从起点出发经过目标点,每个棋子都是一起移动的。在 2nm步内,要求所有棋子都经过目标点,不一定需要落在目标点
思路:只需要全都移动到左上角,然后一起移动走过整个棋盘

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=200+10;
int n,m,k;
pair<int,int> p;

int main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=2*k;++i)
        cin>>p.first>>p.second;

    string ans;
    for(int i=1;i<=m-1;++i)
        ans+='L';
    for(int i=1;i<=n-1;++i)
        ans+='U';
    for(int i=1;i<=n;++i)
    {
        if(i&1)
        {
            for(int j=1;j<=m-1;++j)
                ans+='R';
        }
        else
        {
            for(int j=1;j<=m-1;++j)
                ans+='L';
        }
        if(i!=n)
            ans+='D';
    }
    cout<<ans.size()<<"\n";
    cout<<ans<<"\n";
    return 0;
}

D. Infinite Path

在这里插入图片描述
题意:让你找一个最小的k,使得在一条无穷路径上的各个颜色都相同
思路:其实就是在一个环上跑, p k p^k pk 就表示步长为k。然后我们需要使得在这个路径上颜色都相同。

  • 有一个结论:环长为 L ,步长为 K ,那么就会走遍 gcd(K,L)所有的倍数经过的点
  • 因此只需要枚举长度 环长 l 的因子就好了。然后对每个步长,还得枚举一下起点,最后判断颜色是否相同即可
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+10,inf=0x3f3f3f3f;

int t,n;
int p[maxn],c[maxn],visit[maxn];
vector<int> d[maxn];

int main()
{
    for(int i=1;i<=200000;++i)
        for(int j=i;j<=200000;j+=i)
            d[j].push_back(i);

    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=1;i<=n;++i)
            cin>>p[i];
        for(int i=1;i<=n;++i)
            cin>>c[i],visit[i]=0;
        int ans=inf;
        for(int i=1;i<=n;++i)
        {
            if(visit[i])
                continue;

            vector<int> loop;
            int u=i;
            while(!visit[u])
            {
                visit[u]=1;
                loop.push_back(u);
                u=p[u];
            }

            int m=loop.size();
            for(auto k : d[m])
            {
                for(int r=0;r<k;++r)
                {
                    bool same=1;
                    for(int j=r;j<m;j+=k)
                        same&=(c[loop[r]]==c[loop[j]]);
                    if(same)
                        ans=min(ans,k);
                }
            }
        }
        cout<<ans<<"\n";
    }
    return 0;
}

E. Count The Blocks

在这里插入图片描述

思路:假设有 x 块相同的放在一起

  • 放在最左边和最右边是一样的排列数是: 9 × 1 0 n − x − 1 × 2 9\times 10^{n-x-1} \times 2 9×10nx1×2
  • 放在最中间的有: 9 × 9 × 1 0 n − x − 2 × ( n − 2 − x + 1 ) 9\times 9 \times 10^{n-x-2}\times(n-2-x+1) 9×9×10nx2×(n2x+1)
  • 最后再乘上 10(10个数)
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+10,mod=998244353;

int n;
ll a[maxn],p[maxn];

int main()
{
    cin>>n;
    p[0]=1;
    for(int i=1;i<=200000;++i)  p[i]=p[i-1]*10%mod;
    for(int i=1;i<=n-1;++i)
    {
        a[i]=9ll*p[n-i-1]%mod*2%mod+(n-2-i+1)*81%mod*p[n-2-i]%mod;
        a[i]=a[i]%mod*10%mod;
    }
    a[n]=10;
    for(int i=1;i<=n;++i)
        cout<<a[i]<<" ";
    cout<<"\n";
    return 0;
}

F. AND Segments

在这里插入图片描述

把每一位都拿出来看,这个问题就是在解决这样一个问题:
在长度为 n 的区间上,在某些 [ l , r ] 的区间上只能填 1 ,在某些区间上,至少需要填 一个 0 ,其余没有限制的位置可以 0 1 任意填,问满足条件的方案数

思路

  • d p [ i ] [ j ] dp[i][j] dp[i][j] 表示前 i 个数上一个0的位置为 j 的方案数
    当前位置 i 放 1 : d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i1][j],方案数就是上一个j的方案数
    当前位置 i 放 0 : d p [ i ] [ i ] = ∑ k = 1 i − 1 d p [ i − 1 ] [ k ] dp[i][i]=\sum_{k=1}^{i-1}dp[i-1][k] dp[i][i]=k=1i1dp[i1][k],此时的方案数由前面任何一个位置放零的方案数转移过来。
    为什么是 d p [ i ] [ i ] dp[i][i] dp[i][i]而不是 d p [ i ] [ j ] dp[i][j] dp[i][j],因为当前是第 i 个位置,这里放 0 的话,上一个出现 0 的位置就是 i
  • 最后答案就是: ∑ j = 1 n d p [ n ] [ j ] \sum_{j=1}^n dp[n][j] j=1ndp[n][j]表示离 n 最近的一个 0 ,最终出现在 [1,n]的每个位置的方案数
  • 优化一下:
    g [ i ] [ j ] = ∑ k = 1 j d p [ i ] [ k ] g[i][j]=\sum_{k=1}^j dp[i][k] g[i][j]=k=1jdp[i][k],则 d p [ i ] [ j ] = g [ i − 1 ] [ j − 1 ] dp[i][j]=g[i-1][j-1] dp[i][j]=g[i1][j1]
  • 再把第一维取消掉:
    当前位置 i 放 1 : d p [ j ] = d p [ j ] dp[j]=dp[j] dp[j]=dp[j] g [ j ] = g [ j − 1 ] g[j]=g[j-1] g[j]=g[j1]
    当前位置 i 放 0 : d p [ j ] = g [ j − 1 ] dp[j]=g[j-1] dp[j]=g[j1] g [ j ] = g [ j − 1 ] + d p [ j ] g[j]=g[j-1]+dp[j] g[j]=g[j1]+dp[j]
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=5e5+10,mod=998244353;
int n,k,m;
struct node
{
    int l,r,x;
}nn[maxn];
int dp[maxn],g[maxn],co[maxn],maxl[maxn];

int main()
{
    scanf("%d%d%d",&n,&k,&m);
    for(int i=1;i<=m;++i)
        scanf("%d%d%d",&nn[i].l,&nn[i].r,&nn[i].x);
    int ans=1;
    for(int t=0;t<k;++t)
    {
        for(int i=1;i<=n;++i)
            maxl[i]=dp[i]=g[i]=co[i]=0;
        for(int i=1;i<=m;++i)
        {
            int l=nn[i].l,r=nn[i].r;
            if(nn[i].x>>t&1)
                co[l]++,co[r+1]--;
            else
                maxl[r]=max(maxl[r],l);
        }
        dp[0]=g[0]=1;
        int p=0,pref=0;// p 不能改成 1,最初 0是合法位置
        for(int j=1;j<=n;++j)
        {
            pref+=co[j];
            if(pref)
                g[j]=g[j-1];
            else
            {
                dp[j]=g[j-1];
                g[j]=(g[j-1]+dp[j])%mod;
            }
            while(p<maxl[j])//减去上一个0在当前区间外的方案数
                g[j]=(g[j]-dp[p]+mod)%mod,p++;
        }
        ans=1ll*ans*g[n]%mod;
    }
    printf("%d\n",ans);
    return 0;
}
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=5e5+10,mod=998244353;
int n,k,m;
struct node
{
    int l,r,x;
}nn[maxn];
int dp[maxn],g[maxn],co[maxn],maxl[maxn];

int main()
{
    scanf("%d%d%d",&n,&k,&m);
    for(int i=1;i<=m;++i)
        scanf("%d%d%d",&nn[i].l,&nn[i].r,&nn[i].x);
    int ans=1;
    for(int t=0;t<k;++t)
    {
        for(int i=1;i<=n;++i)
            maxl[i]=dp[i]=g[i]=co[i]=0;
        for(int i=1;i<=m;++i)
        {
            int l=nn[i].l,r=nn[i].r;
            if(nn[i].x>>t&1)
                co[l]++,co[r+1]--;
            else
                maxl[r]=max(maxl[r],l);
        }
        dp[0]=g[0]=1;
        int l=0,pref=0;// l不能改成 1,最初 0是合法位置
        for(int j=1;j<=n;++j)
        {
            pref+=co[j];
            if(pref)
                g[j]=g[j-1];
            else
            {
                dp[j]=g[j-1];
                g[j]=(g[j-1]+dp[j])%mod;
                if(l>=1)
                    g[j]=(g[j]-g[l-1]+mod)%mod;
            }
            l=max(maxl[j],l);
        }
        ans=1ll*ans*(g[n]-g[l-1]+mod)%mod;
    }
    printf("%d\n",ans);
    return 0;
}

贴一份学长代码

#include <bits/stdc++.h>
using namespace std;
#define rep(i,s,t) for(int i=s;i<t;i++)
#define pii pair<int,int>
typedef long long ll;
const ll mod=998244353;
#define MAXNUM 555555
struct node{int l,r,x;};
ll dp[MAXNUM],sum[MAXNUM],co[MAXNUM];
int maxl[MAXNUM];
node nn[MAXNUM];
int main()
{
    int n,m,k;
    scanf("%d%d%d",&n,&k,&m);
    rep(i,1,m+1)scanf("%d%d%d",&nn[i].l,&nn[i].r,&nn[i].x);
    ll r=1;
    rep(i,0,k)
    {
        rep(i,1,n+1)co[i]=sum[i]=maxl[i]=0;
        rep(j,1,m+1)
        {
            if((nn[j].x>>i)&1)
                co[nn[j].l]++,co[nn[j].r+1]--;
            else maxl[nn[j].r]=max(maxl[nn[j].r],nn[j].l);
        }
        sum[0]=1;
        int nows=0,nowmax=0;
        rep(j,1,n+1)
        {
            nows+=co[j];
            if(nows)sum[j]=sum[j-1];
            else sum[j]=(2*sum[j-1]-sum[nowmax-1]+mod)%mod;
            nowmax=max(maxl[j],nowmax);
        }
        r=r*(sum[n]-sum[nowmax-1]+mod)%mod;
    }
    printf("%lld\n",r);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值