【CF】 Educational Codeforces Round 56 (Rated for Div. 2)
ac被虐后,div2cf又惨遭横祸。。真的菜啊orz
cfcfcf
A题:给定一个数,一个点数2-7的筛子,给定询问x,回答一种可能的总和加起来为x的次数。
奇数-3之后当偶数考虑,x/2便为一种可能的次数。
#include<stdio.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int T;
int main() {
scanf("%d",&T);
while(T--) {
int ans = 0;
int x; scanf("%d",&x);
if(x<=3) { puts("1"); continue; }
if(x&1) x-=3,ans++;
ans += x/2;
printf("%d\n",ans);
}
}
B题:给定一个字符串,构造一种方案使得他不为回文串,如果没有方案输出-1.
直接把字符串排序之后判断他还是不是回文串即可。
#include<stdio.h>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
char ss[1005]; int len;
void solve() {
scanf("%s",&ss[1]);
len = strlen(ss+1);
sort(ss+1,ss+1+len);
bool fl = 0;
for(int i=1,j=len;i<=j;i++,j--) {
if(ss[i]!=ss[j]) {
fl = 1; break;
}
}
if(!fl) puts("-1");
else {
for(int i=1;i<=len;i++) putchar(ss[i]);
puts("");
}
}
int main() {
int T;
scanf("%d",&T);
while(T--) {
solve();
}
}
C题:给定一个串B,长度为n/2,求一个串A,长度,使得满足Ai+An-i+1 == Bi,保证有解。
考虑每一个B,他对应的Ai限制条件分别由Ai-1和An-i+2限制,在考虑完他们的限制之后贪心Ai选最小,An-i+1选最大。
#include<stdio.h>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
typedef unsigned long long ll;
const int maxn = 200005;
int n;
ll b[maxn];
ll a[maxn];
int main() {
cin>>n; n/=2;
ll mx,mi;
cin>>b[1];
a[0] = 0; a[2*n]=b[1];
for(int i=2;i<=n;i++) {
cin>>b[i];
ll oo;
mx = min(a[2*n-i+2],b[i]);
mi = max(a[i-1],b[i]-mx);
a[i] = mi; a[2*n-i+1] = b[i]-a[i];
}
for(int i=1;i<=2*n;i++) cout<<a[i]<<' ';
}
D题:给一张图,给每个点选择数字(1,2,3)其中一种,使得边的两边总为奇数的方案。
由于图可能不联通,所以对于每个子图跑一个二分图染色之后,乘法原理方案相乘。
#include<stdio.h>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
typedef unsigned long long ll;
const int maxn = 200005;
int n;
ll b[maxn];
ll a[maxn];
int main() {
cin>>n; n/=2;
ll mx,mi;
cin>>b[1];
a[0] = 0; a[2*n]=b[1];
for(int i=2;i<=n;i++) {
cin>>b[i];
ll oo;
mx = min(a[2*n-i+2],b[i]);
mi = max(a[i-1],b[i]-mx);
a[i] = mi; a[2*n-i+1] = b[i]-a[i];
}
for(int i=1;i<=2*n;i++) cout<<a[i]<<' ';
}
E:给定两个1,,n的排列a,b,每次询问(la,ra) (lb,rb)即询问两个排列的两个区间中有多少个相同的数字,修改是交换两个b排列中的数。
离散化之后,问题转化为单点删除添加,矩形查询点数,树套树就可以了。不想写orz
F题:给n1e5,len1e5,k100给定一个数字范围在[1,k]或者为-1的长度n数组,求把这个数组所有为-1的数改为[1,k]之间的数之后满足不存在长度大于等于len的区间,区间所有的数相同方案数%998244353。
一个十分巧妙的dp, F[i][j]表示当前考虑到数组第i位,第i位填j的方案数。那么f[i][j] = sum f[i][1-->k] - sum[i-len][1-->k] + dp[i-len][j],即直接在后面添一个j,并且减去前面长度len-1位都为j的方案数,再加上i-len位为j的方案数(因为前len-1位都为j,因为前面的方案都保证合法然而减去的方案中包含了i-len为j,那么就是减多了方案就加回来)。
#include<stdio.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 200005;
const int mod = 998244353;
int add(int x,int y) {
x+=y; return x>=mod?x-mod:x;
}
int sumdp[maxn],dp[maxn][105];
int len,k,n,nm[maxn],cnt[105][maxn];
int main() {
scanf("%d%d%d",&n,&k,&len);
if(len==1) {
puts("0"); return 0;
}
for(int i=1;i<=n;i++) {
scanf("%d",&nm[i]);
for(int j=1;j<=k;j++) {
cnt[j][i] = cnt[j][i-1] + (nm[i]==-1||nm[i]==j);
}
}
if(nm[1]==-1) { for(int j=1;j<=k;j++) dp[1][j] = 1; sumdp[1]=k; }
else dp[1][nm[1]] = 1,sumdp[1]=1;
for(int i=2;i<=n;i++) {
if(nm[i]!=-1) {
int j = nm[i];
dp[i][j] = sumdp[i-1];
if(i<len||cnt[j][i]-cnt[j][i-len]!=len) goto zz;
if(i==len) dp[i][j] = add(dp[i][j],mod-1);
else dp[i][j] = add(dp[i][j],add(mod-sumdp[i-len],dp[i-len][j]));
} else {
for(int j=1;j<=k;j++) {
dp[i][j] = sumdp[i-1];
if(i<len||cnt[j][i]-cnt[j][i-len]!=len) continue;
if(i==len) dp[i][j] = add(dp[i][j],mod-1);
else dp[i][j] = add(dp[i][j],add(mod-sumdp[i-len],dp[i-len][j]));
}
}
zz:for(int j=1;j<=k;j++) sumdp[i] = add(sumdp[i],dp[i][j]);
}
printf("%d",sumdp[n]);
}
G题:6s q , n 2e5 ai 1e6 k 5 给定一个序列,这个序列里的每一个元素由一个k元组构成,定义两个k元组之间的距离为这两个组里面对应的那一元的差的绝对值的和。
[latex]\sum \limits_{i = 1}^{k} |a_{x, i} - a_{y, i}| [/latex]
考虑转化原式子为(抄自官方题解): [latex] \sum \limits_{i = 1}^{k} |a_{x, i} - a_{y, i}| = \sum \limits_{i = 1}^{k} c_i (a_{x, i} - a_{y, i}) = \sum \limits_{i = 1}^{k} c_i a_{x, i} - \sum \limits_{i = 1}^{k} c_i a_{y, i}[/latex] where ci=1 if ax,i≥ay,i, otherwise ci=−1.
然后我们发现对于这样的一个式子,如果我们在原本的基础上修改取反c的符号,最终这个值一定是不会变大的,也就是说对于两个k元组他们最终的距离一定就是枚举c符号后最大的那个值。
所以做法就比较明了了,枚举c的符号,区间找到最大的 [latex] \sum \limits_{i = 1}^{k} c_i a_{x, i} [/latex] 和 [latex] \sum \limits_{i = 1}^{k} - c_i a_{y, i} [/latex] 即可,线段树之。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
const int maxn = 400005;
int n,k,S;
int A[maxn][6];
struct node{
node *ls,*rs;
int a[1<<5];
}z[maxn],*rt; int tot;
void mktree(node *&p,int L,int R) {
p = &z[++tot];
if(L==R) {
for(int s=0;s<=S;s++) {
for(int j=1;j<=k;j++) {
if(s>>(j-1)&1) p->a[s] += A[L][j];
else p->a[s]-=A[L][j];
}
}
return;
}
int mid = (L+R)>>1;
mktree(p->ls,L,mid); mktree(p->rs,mid+1,R);
for(int s=0;s<=S;s++) {
p->a[s] = max(p->ls->a[s],p->rs->a[s]);
}
}
void change(node *&p,int L,int R,int x) {
if(L==R) {
for(int s=0;s<=S;s++) {
p->a[s] = 0;
for(int j=1;j<=k;j++) {
if(s>>(j-1)&1) p->a[s] += A[L][j];
else p->a[s]-=A[L][j];
}
}
return;
}
int mid = (L+R)>>1;
if(x<=mid) change(p->ls,L,mid,x);
else change(p->rs,mid+1,R,x);
for(int s=0;s<=S;s++) {
p->a[s] = max(p->ls->a[s],p->rs->a[s]);
}
}
int query(node *&p,int l,int r,int x,int y,int s) {
if(x<=l&&r<=y) return p->a[s];
int mid = (l+r)>>1;
if(x>mid) return query(p->rs,mid+1,r,x,y,s);
else if(y<=mid) return query(p->ls,l,mid,x,y,s);
else return max(query(p->ls,l,mid,x,y,s),query(p->rs,mid+1,r,x,y,s));
}
int main() {
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) {
for(int j=1;j<=k;j++) {
scanf("%d",&A[i][j]);
}
}
S = (1<<k)-1;
mktree(rt,1,n);
int q; scanf("%d",&q);
while(q--) {
int op;scanf("%d",&op);
if(op==1) {
int x; scanf("%d",&x);
for(int i=1;i<=k;i++) {
scanf("%d",&A[x][i]);
}
change(rt,1,n,x);
} else {
int L,R; scanf("%d%d",&L,&R);
int ans = 0;
for(int i=0;i<(1<<(k-1));i++) {
ans = max(ans,query(rt,1,n,L,R,i) + query(rt,1,n,L,R,S^i) );
}
printf("%d\n",ans);
}
}
}

浙公网安备 33010602011771号