Educational Codeforces Round 84 Rated for Div. 2
比赛链接 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
n≥2(1+2k−1)×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×10n−x−1×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×10n−x−2×(n−2−x+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[i−1][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=1i−1dp[i−1][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[i−1][j−1] - 再把第一维取消掉:
当前位置 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[j−1]
当前位置 i 放 0 : d p [ j ] = g [ j − 1 ] dp[j]=g[j-1] dp[j]=g[j−1], g [ j ] = g [ j − 1 ] + d p [ j ] g[j]=g[j-1]+dp[j] g[j]=g[j−1]+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);
}