CF1710 题解
比赛链接:https://codeforces.com/contest/1711
BD比以往的要难,E要更简单
A
水题
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f;
signed main(){
int te;scanf("%d",&te);
while(te --){
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)printf("%d ", i == 1? n : i-1);
puts("");
}
return 0;
}
B
如果一共有偶数对的话,显然全邀请最优
否则有奇数对,考虑某一对 \((a,b)\),显然如果 \(a\) 或者 \(b\) 在配对中出现了奇数次,就不邀请这个人,首先肯定满足偶数对条件,其次用这个人的 \(a\) 来更新答案,如果二者都出现了偶数次,那么同时删去 \(a\) 和 \(b\) 的话,最后还是偶数对(ab重复了一次),更新答案
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 1e5+5;
int n,m;
int a[maxn], vis[maxn];
pii fr[maxn];
void solve(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]), vis[i] = 0;
for(int i=1;i<=m;i++){
scanf("%d%d",&fr[i].first,&fr[i].second);
++ vis[fr[i].first]; ++ vis[fr[i].second];
}
int res = 0;
for(int i=1;i<=n;i++)if(!vis[i])res += a[i];
if(m%2 == 0){
puts("0");
return ;
}
int r = 1e9;
for(int i=1;i<=m;i++){
int c = 0;
int u=fr[i].first,v=fr[i].second;
if(vis[u]&1)r=min(r,a[u]);
if(vis[v]&1)r=min(r,a[v]);
if(vis[u]%2==0&&vis[v]%2==0)r=min(r,a[u]+a[v]);
}
printf("%d\n",r);
}
signed main(){
int te;scanf("%d",&te);
while(te--)solve();
return 0;
}
C
行列同理,先讨论行
显然只能一整行一整行的画,而且相同颜色的行至少有两行
因此我们考虑一下统计能画超过2行的颜料数量,然后判一下能否画完就行了
有个反例:如果有5行,所有颜料都只能画2行,这样也是不行的。因此再判一下有没有能画超过2行的就行了
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 1e5 + 5;
int n,m,k;
int a[maxn], b[maxn], c[maxn];
void solve(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=k;i++)scanf("%d",&a[i]), b[i] = a[i] / n, c[i] = a[i] / m;
// if(n%2==1 && m%2==1){
// puts("NO");return ;
// }
LL fg1=0, fg2=0, fg3=0, fg4=0, fg01=0, fg03=0;
for(int i=1;i<=k;i++){
if(b[i] >= 2){
fg1 += b[i];
++ fg01;
if(b[i] > 2)++ fg2;
}
if(c[i] >= 2){
fg3 += c[i];
++ fg03;
if(c[i] > 2)++ fg4;
}
}
if(m%2 == 0){
if(fg1>=m){puts("Yes");return ;}
}else{
if(fg1>=m && fg2){puts("Yes");return ;}
}
if(n%2 == 0){
if(fg3>=n){puts("Yes");return ;}
}else{
if(fg3>=n && fg4){puts("Yes");return ;}
}
puts("No");
}
signed main(){
int te;scanf("%d",&te);
while(te--)solve();
return 0;
}
D
转化的比较神仙。
详见https://www.luogu.com.cn/problem/solution/CF1710B
大体思路就是将原来的降水和枚举删去哪一天降水分开,然后转化了一波模型变成了原来的降水能不能包含在 m + 枚举的降水 这个平面内
然后再转化,考虑原来的降水能被包含在哪些平面里面,发现相当于一个平面求交,所有的斜率都是 +1 -1,因此可以用截距表示(b0 b1)
最后判断是否在平面内的时候也可以用截距
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <map>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>
#define int LL
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f;
map<int,int>mp;
int n,m,x[200005],p[200005];
void solve(){
cin>>n>>m;
mp.clear();
for(int i=1;i<=n;i++){
cin>>x[i]>>p[i];
mp[x[i]-p[i]]++;
mp[x[i]]-=2;
mp[x[i]+p[i]]++;
}
int k=0, lst=-inf, cur=0;
int b0=-inf, b1=-inf;
for(auto it : mp){
cur += k * (it.first - lst);
k += it.second;
if(cur > m){
b0=max(b0,it.first+cur);
b1=max(b1,cur-it.first);
}
lst = it.first;
}
for(int i=1;i<=n;i++){
if(p[i]+m-x[i] >= b1 && p[i]+m+x[i] >= b0)
cout<<1;
else cout<<0;
}
puts("");
}
signed main(){
int te;cin>>te;
while(te--)solve();
return 0;
}
E
数位dp傻逼题
比如考虑\(b \ xor\ a + b \ xor\ c > a \ xor\ c\)这个式子该如何满足,将abc赋值0/1打表发现只有2种情况,因此可以在状态中加一个0/1表示是否已经满足了,因为如果当前位满足了,剩下的位无论如何也一定满足题目条件
一遍写完过编译过样例AC好爽
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 2e5 + 5, mod = 998244353;
char s[maxn];
int n;
int dp[maxn][2][2][2][2][2][2]; // 考虑到第 i 位,abc与上界关系,三个限制是否满足
void add(int &x,int y){(x+=y)%=mod;}
int dfs(int x,int t1,int t2,int t3,int lim0,int lim1,int lim2){
int &dd = dp[x][t1][t2][t3][lim0][lim1][lim2];
if(x == n+1){
if(t1+t2+t3 == 3)
return dd = 1;
else return dd = 0;
}
if(~dd)return dd;
int up0 = lim0 ? s[x] - '0' : 1;
int up1 = lim1 ? s[x] - '0' : 1;
int up2 = lim2 ? s[x] - '0' : 1;
int cur = 0;
#define limit lim0&&a==up0,lim1&&b==up1,lim2&&c==up2
for(int a=0;a<=up0;a++){
for(int b=0;b<=up1;b++)
for(int c=0;c<=up2;c++){
if(b==1&&a+c==0)add(cur, dfs(x+1,t1,1,t3,limit));
else if(b==0&&a+c==2)add(cur, dfs(x+1,t1,1,t3,limit));
else{
if(a==0&&b+c==2)add(cur, dfs(x+1,1,t2,t3,limit));
else if(a==1&&b+c==0)add(cur, dfs(x+1,1,t2,t3,limit));
else{
if(c==1&&a+b==0)add(cur, dfs(x+1,t1,t2,1,limit));
else if(a+b==2&&c==0)add(cur, dfs(x+1,t1,t2,1,limit));
else add(cur,dfs(x+1,t1,t2,t3,limit));
}
}
}
}
return dd = cur;
}
signed main(){
memset(dp,-1, sizeof dp);
scanf("%s",s + 1);
n = strlen(s + 1);
int ans = dfs(1,0,0,0,1,1,1);
printf("%d\n",ans);
return 0;
}