CF1754 题解
比赛链接:https://codeforces.com/contest/1754
题解:
AB
水题
// by SkyRainWind
#include <cstdio>
#include <vector>
#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--){
char s[1005];
int n;
scanf("%d",&n);
scanf("%s", s+ 1);
int gg = 0, st = 0;
for(int i=n;i>=1;i--)
if(s[i] == 'Q'){
if(st<=0){gg =1 ;break;}
-- st;
}else ++ st;
if(gg) puts("No");
else puts("Yes");
}
return 0;
}
// by SkyRainWind
#include <cstdio>
#include <vector>
#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);
if(n&1){
for(int i=n/2+1;i>=3;i--)printf("%d %d ",i,i+n/2);
printf("2 %d 1 ",2+n/2);
}
else{
for(int i=n/2;i>=1;i--)printf("%d %d ",i,i+n/2);
}
puts("");
}
return 0;
}
C1 & C2
显然减法比较容易处理,算出总和,然后枚举哪些位置有减法,由于只有-1/0/1,所以有1就尽量减,注意要减两次(因为一开始加了一次)
// by SkyRainWind
#include <cstdio>
#include <vector>
#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;
int n, a[maxn];
void solve(){
int s =0;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]), s+= a[i];
if(s & 1){
puts("-1");
return ;
}
vector<pii>ans;
for(int i=2;i<=n;i++){
if((s>0 && a[i] == 1) || (s < 0 && a[i] == -1))s -= 2 * a[i], ans.push_back(mpr(i-1,i)), ++ i;
}
if(s == 0){
printf("%d\n",n - ans.size());
int lst = 1;
for(pii i : ans){
for(int j=lst;j<i.first;j++)printf("%d %d\n",j, j);
printf("%d %d\n",i.first,i.second);
lst = i.second + 1;
}
for(int i=lst;i<=n;i++)printf("%d %d\n",i,i);
}else puts("-1");
}
signed main(){
int te;scanf("%d",&te);
while(te --)solve();
return 0;
}
D
如果有(n+1)个n!,就能凑出一个(n+1)!,如果存在某个地方p!不能合并且<x,那么一定不可能实现
// by SkyRainWind
#include <cstdio>
#include <vector>
#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=5e5+5;
int n,k,a[maxn], cnt[maxn];
signed main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),++ cnt[a[i]];
for(int i=1;i<k;i++){
cnt[i+1] += cnt[i] / (i+1), cnt[i] %= (i+1);
if(cnt[i])return puts("No"), 0;
}
if(cnt[k])puts("Yes");
else puts("No");
return 0;
}
E
设一共有s个0,前s个数中有r个0
显然当前状态只与r有关,那么设\(dp[i]\)表示前s个数中有i个0的期望步数,那么显然\(dp[s]=0\),要求\(dp[r]\)
记\(p=2*(s-r)*(s-r) /((n-1) * n)\),代表前s中的1和后n-s中的0发生交换的概率
那么有\(dp[k] = 1 + dp[k] * p + dp[k+1] * (1-p)\),感觉就是\((dp[k]+1) * p\)和\((dp[k+1]+1) * p\)相加之后得出的+1
// by SkyRainWind
#include <cstdio>
#include <vector>
#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, mod = 998244353,maxn=2e5+5;
int pw(int x,int y){
if(!y)return 1;
if(y == 1)return x;
int mid = pw(x, y>>1);
if(y & 1)return 1ll*mid*mid%mod*x%mod;
return 1ll*mid*mid%mod;
}
int dp[maxn],n,a[maxn];
void solve(){
int s = 0, r = 0;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]), s += a[i] == 0;
for(int i=1;i<=s;i++)r += a[i] == 0;
dp[s] = 0;
for(int k = s-1; k >= r;k--){
int p = 2ll * (s - k) * (s - k)%mod * pw(1ll * n * (n-1)%mod, mod-2) % mod;
dp[k] = (pw(p, mod-2) + dp[k+1] ) %mod;
}
printf("%d\n",dp[r]);
}
signed main(){
int te;scanf("%d",&te);
while(te --)solve();
return 0;
}
F
首先明确一点:一个床最多移动一个位置(否则两个都移动一定存在一个方案,至多移动1个位置就可以找出一个1*2的部分)
考虑建图:如果(i,j)为L,那么像(i-1,j+1) (i+1,j+1) (i,j+2) 连一条反向边,权值就是p/p/q,其余位置同理
如果从'.'开始,这个图上的一条路径就表示所经过的点都能变成'.'(到哪个点就移动相应位置的床即可)
到某个点的最短路径就代表这个位置变成.所需要的最小代价
显然一张图上i+j按奇偶性分成了两张独立的图,又结合上面的性质,一张床最多移动一个位置,因此不需要担心跑完多个最短路之后一个床都被移动导致的错误情况
所以从每个'.'跑多个dijkstra即可
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
#include <iostream>
#include <string>
#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;
#define int LL
const int inf = 1e9, INF = 0x3f3f3f3f, maxn=3e5 + 5;
int n,m,p,q;
int ind(int x,int y){return x * m + y;}
int f[maxn];
string s[maxn];
vector<pair<int,int> >g[maxn];
int dp[maxn], dis[maxn];
void add(int x,int y,int w,int id){
if(x < 0 || x >=n || y < 0 || y >=m )return ;
g[ind(x,y)].push_back(mpr(id,w));
}
priority_queue<pii,vector<pii>,greater<pii>>qu;
signed main(){
memset(dp,0x3f,sizeof dp);
scanf("%I64d%I64d%I64d%I64d",&n,&m,&p,&q);
for(int i=0;i<n;i++)cin >> s[i];
for(int i=0;i<n;i++)
for(int j =0;j<m;j++){
int id = ind(i,j);
if(s[i][j] == 'L')add(i,j+2,q,id),add(i+1,j+1,p,id),add(i-1,j+1,p,id);
if(s[i][j] == 'R')add(i,j-2,q,id),add(i+1,j-1,p,id),add(i-1,j-1,p,id);
if(s[i][j] == 'U')add(i+2,j,q,id),add(i+1,j+1,p,id),add(i+1,j-1,p,id);
if(s[i][j] == 'D')add(i-2,j,q,id),add(i-1,j+1,p,id),add(i-1,j-1,p,id);
}
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(s[i][j] == '.')qu.push(mpr(0,ind(i,j))), dp[ind(i,j)] = 0;
while(!qu.empty()){
pii tp = qu.top();qu.pop();
int id = tp.second;
if(dp[id] != tp.first)continue; // 已经更新过最短路了
for(pii now : g[id]){
int u = now.first, v = now.second;
if(dp[u] > dp[id] + v)qu.push(mpr(dp[u] = dp[id] + v, u));
}
}
LL ans = 1e18;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
if(i+1 < n)ans = min(ans, dp[ind(i,j)] + dp[ind(i+1,j)]);
if(j+1 < m)ans = min(ans, dp[ind(i,j)] + dp[ind(i,j+1)]);
}
if(ans == 1e18)puts("-1");
else printf("%I64d\n",ans);
return 0;
}