2020-03-24 11:07阅读: 309评论: 0推荐: 1

Educational Codeforces Round 84 (Rated for Div. 2)

A. Sum of Odd Integers (CF 1327 A)

题目大意

给定n,k,问n是否能表示成k个互不相同的奇数的和。

解题思路

首先nk的奇偶性要相同,其次k个互不相同的奇数的和的最小值为1+3+5+...+2k1=k2,所以需要nk2

神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main(void) {
int t;
cin>>t;
while(t--){
LL n,k;
cin>>n>>k;
bool qwq=false;
if ((n-k)%2==0&&n>=k*k) puts("YES");
else puts("NO");
}
return 0;
}


B. Princesses and Princes (CF 1327 B)

题目大意

n个公主与n个王子配对,每个公主有几个王子的配对意愿。对于标号从小到大的每个公主,找公主有配对意愿的王子中最小编号的且未配对的与公主配对。问能否再增加一条配对意愿,使得最终得以配对的公主数增加,能则输出任意一条配对意愿。

解题思路

直接模拟,最后看是否n个公主都配对了,不是则找一个未配对的公主和未配对的王子给他们增加一条配对意愿即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int main(void) {
int t;
read(t);
while(t--){
int n;
read(n);
bool sign[n+1]={0};
int dau=-1;
for(int i=1;i<=n;++i){
int k;
read(k);
bool qwq=false;
for(int u,j=1;j<=k;++j){
read(u);
if (!qwq&&!sign[u]) {sign[u]=true; qwq=true;}
}
if (!qwq) dau=i;
}
if (dau==-1) puts("OPTIMAL");
else{
int cur=1;
while(sign[cur]) ++cur;
puts("IMPROVE");
printf("%d %d\n",dau,cur);
}
}
return 0;
}


C. Game with Chips (CF 1327 C)

题目大意

nm的网格,有k个chips。给出了它们的初始位置,然后分别给出每个chip的特定位置,可以进行四种操作:上、下、左、右,即将全部chips向上、下、左、右移动一格,若对于移动会超出边界的chips则在原地不动。问能否在2mn的操作次数内,使得每个chip都能至少达到特定位置一次,能则输出操作。

解题思路

一道滑稽构造题。把全部chips移动到左上角然后再遍历整个网格即可。操作数(n1)+(m1)+(n1)(m1)=nm1

神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main(void) {
int n,m;
cin>>n>>m;
string s;
string quq(n-1,'U');
string qlq(m-1,'L');
string qrq(m-1,'R');
s+=quq;
s+=qlq;
for(int ss=1,i=1;i<=n;++i){
if (ss==1){
s+=qrq;
if (i!=n) s+='D';
ss^=1;
}else{
s+=qlq;
if (i!=n) s+='D';
ss^=1;
}
}
int len=s.size();
cout<<len<<endl<<s<<endl;
return 0;
}


D. Infinite Path (CF 1327 D)

题目大意

给定一个排列p1,p2,,pn,以及每个元素的颜色c1,c2,,cn,同时定义排列的乘法c=a×b,即c[i]=b[a[i]],其中a,b是两个排列。因此我们定义排列的k次方pk=p×p××pk times。求一个最小的正整数k,使得pk排列里存在一个无穷序列。所谓无穷序列就是i,p[i],p[p[i]],p[p[p[i]]],且c[i]=c[p[i]]=c[p[p[i]]]=

解题思路

很显然,如果有自环的话k最小为1

一个排列所形成的置换形成一个个环,我们观察p的次方的定义可知,一个个环之间是相互独立的,所以我们分别考察每个环,看看每个点的颜色是否都相同。

对于一个环来说,有m个点,如果是p1,就相当于对于一个点,它往前一位选一个点,直到已经选到的点为止。而如果是p2,则它往前两位选一个点,直到已经选到的点为止。

如果k选得好,一个环会被拆成k个小环,而如果原来的大环不符合要求,而小环有可能符合要求。至于是哪些k能把大环拆成小环,很容易得知当km的因数的话就能拆成小环。所以我们枚举m的因数分别去判断是否可行,取最小值即可。

第一次在传参时vector没加&然后MLE……

神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
bool check(vector<int> &ji,int st,int step,int c[]){
for(size_t i=st+step;i<ji.size();i+=step){
if (c[ji[i]]!=c[ji[i-step]]) return false;
}
return true;
}
void work(vector<int> &ji,int c[],int &ans){
int cnt=ji.size();
int up=sqrt(cnt);
for(int i=1;i<=up;++i){
if (cnt%i!=0) continue;
for(int j=0;j<i;++j)
if (check(ji,j,i,c)) {
ans=min(ans,i);
break;
}
if (i!=cnt/i) {
for(int j=0;j<cnt/i;++j)
if (check(ji,j,cnt/i,c)) {
ans=min(ans,cnt/i);
break;
}
}
}
}
void DFS(int u,int nxt[],vector<int> &ji,int c[],bool sign[],int &ans){
sign[u]=true;
ji.push_back(u);
if (sign[nxt[u]]) work(ji,c,ans);
else DFS(nxt[u],nxt,ji,c,sign,ans);
}
int main(void) {
int t;
read(t);
while(t--){
int n;
read(n);
bool qwq=false;
int nxt[n+1]={0};
for(int i=1;i<=n;++i){
read(nxt[i]);
if (nxt[i]==i) qwq=true;
}
int c[n+1]={0};
for(int i=1;i<=n;++i){
read(c[i]);
}
if (qwq){
puts("1");
continue;
}
int ans=1e9+7;
bool sign[n+1]={0};
for(int i=1;i<=n;++i){
if (!sign[i]) {
vector<int> ji;
DFS(i,nxt,ji,c,sign,ans);
}
}
write(ans,'\n');
}
return 0;
}


E. Count The Blocks (CF 1327 E)

题目大意

给定n,有10n个数字从010n1,包括前导零使得每个数字都有n位。现在要分别统计长度从1n的数字block的数量。所谓数字block指的是一串连续的相同数位,它不能再往左边或右边拓展(到边界了或者拓展后这串数位不是相同的)

解题思路

一开始以为是数位DP,稍加思索后发现,对于数字block长度为i的数量,分别考虑以每一位开始的长度为i的block对答案的贡献即可。
i<n1时,ans=81×(ni1)×10ni1+18×10ni
i=n1时,ans=18×10ni=180
i=n时,ans=10

神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
const LL mo=998244353;
LL qpower(int a,int b){
LL aa=a;
LL qwq=1;
while(b){
if (b&1) qwq=qwq*aa%mo;
aa=aa*aa%mo;
b>>=1;
}
return qwq;
}
int main(void) {
int n;
read(n);
for(int i=1;i<=n;++i){
LL ans=0;
if (i<n-1) ans=(n-i-1)*81%mo*qpower(10,n-i-1)%mo;
if (i==n) ans=10;
else ans=(ans+18*qpower(10,n-i)%mo)%mo;
write(ans);
}
return 0;
}


F. AND Segments (CF 1327 F)

题目大意

给定n,k,m,有m个要求,表示为(li,ri,xi)。先要求构造一个长度为n的数组a,满足

  • 0ai2k,i[1,n]
  • ali&ali+1&...&ari=xi,i[1,m]

求满足上述两个要求的数组a的数量模998244353

解题思路

&是位运算,我们注意到不同位之间是相互独立的,那么我们就分别计算每一位,每个数在该位的取值的所有情况,最后每一位之间相乘即可得到答案。

对于当前考虑的某一位,对于一个要求(li,ri,xi).

如果xi在该位是1,那么aliali+1...ari在该位都一定是1

如果xi在该位是0,那么aliali+1...ari在该位不能全是1

那么现在就要统计一个长度为n的序列数量,该序列的每个数字是01,且有部分区间的数字全为1,部分区间的数字不能全为1

注意到0是极为特殊的数,我们设dp[i]表示当前是第i个数字,且这个数字为0(或最后一个填0的位置是i)的方案数。

如果这个数字是一定为1的,则dp[i]=0

如果这个数字可以不为1,我们则枚举上一个填0的位置j,由于j+1i1都是填1的,我们不能让这个区间有 不能全为1的区间,所以j应该从i1到 不能全为1的区间 的右端点小于i的那些区间 的最大左端点,记为k,即k=maxrj<ixi0(lj),所以dp[i]=j=ki1dp[j]。这个用前缀和维护就好了。

初始化dp[0]=1。

最后把所有位的dp[n+1]相乘即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
const LL mo=998244353;
int main(void) {
int n,m,k;
read(n);
read(k);
read(m);
vector<pair<pair<int,int>,int>> q(m);
LL ans=1;
for(int l,r,x,i=0;i<m;++i){
read(l);
read(r);
read(x);
q[i]=make_pair(make_pair(l,r),x);
}
for(int i=0;i<k;++i){
int sign[n+5]={0};
int qwq[n+5]={0};
for(auto & j:q){
if (j.second&1){
sign[j.first.first]++;
sign[j.first.second+1]--;
}else{
qwq[j.first.second+1]=max(j.first.first,qwq[j.first.second+1]);
}
j.second>>=1;
}
LL sum[n+5]={0};
sum[0]=1;
int cnt=0;
int pos=0;
for(int j=1;j<=n+1;++j){
cnt+=sign[j];
pos=max(pos,qwq[j]);
if (cnt) sum[j]=sum[j-1];
else if (pos!=0) sum[j]=((sum[j-1]+sum[j-1])%mo-sum[pos-1]+mo)%mo;
else sum[j]=(sum[j-1]+sum[j-1])%mo;
}
ans=((sum[n+1]-sum[n]+mo)%mo*ans)%mo;
}
write(ans,'\n');
return 0;
}


本文作者:~Lanly~

本文链接:https://www.cnblogs.com/Lanly/p/12557669.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(309)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.