cf 板刷日记(1700-1900)二
D. Find the Last Number
Codeforces Round 1061 (Div. 2)
https://codeforces.com/problemset/problem/2156/D
交互题,每次查询所有数某一位的值,看看这一位 0/1 出现的数量哪一个和实际数量不符,则答案的这一位就是几
每次可以排除一半,所以查询差不多就是 \(2*n\) 次
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
int query(int i,int x){
cout<<"? "<<i<<" "<<x<<endl;
int res;
cin>>res;
return res;
}
void solve(){
int n;
cin>>n;
vector<int> t,ans;
for(int i=1;i<n;i++){
t.push_back(i);
ans.push_back(i);
}
ans.push_back(n);
int j=0;
while(t.size()){
vector<vector<int>> mp(60,vector<int>(2));
for(auto i:ans){
int j=0,val=i;
for(int k=0; k<20; k++){
int now = (i >> k) & 1;
mp[k][now]++;
}
}
vector<int> o,l,tmp;
int c0=0,c1=0;
for(auto idx:t){
int res=query(idx,(1<<j));
if(res==0){
o.push_back(idx);
c0++;
}
else{
l.push_back(idx);
c1++;
}
}
if(c0<mp[j][0]){
t=o;
for(auto val:ans){
if(((val>>j)&1)==0) tmp.push_back(val);
}
ans=tmp;
}
else{
t=l;
for(auto val:ans){
if(((val>>j)&1)) tmp.push_back(val);
}
ans=tmp;
}
j++;
}
cout<<"! "<<ans.back()<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
}
D. Batteries
Codeforces Round 1056 (Div. 2)
https://codeforces.com/problemset/problem/2155/D
妙妙题
限制条件是 \(n*n/a\) 次查询,考虑如何利用 \(a\) 这个信息
假设将 \(n\) 个点连成一个环,则两个能用的电池之间的距离不超过 \(n/a\)。
所以对每个点,可以暴力判断后面的 \(n/a\) 个点。一定能找到答案,
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n,a;
cin>>n;
for(int a=1;a<=n;a++){
for(int i=1;i<=n;i++){
if(i+a>n) cout<<i<<" "<<i+a-n<<endl;
else cout<<i<<" "<<i+a<<endl;
int res;
cin>>res;
if(res) return;
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
}
D. Catshock
Codeforces Round 1060 (Div. 2)
https://codeforces.com/problemset/problem/2154/D
真有 1900 吗能让我这么容易的切出来
称 \(1-n\) 简单路径上的点为主线,其他点为直线
大致思路是,先把支线的点按照深度从深到浅删完,再把主线的点从 \(1\) 到 \(n\) 删完
删支线点时,将所有支线点按照深度从大到小排序,每次删最深的那个点。
如果当前猫猫所在点的寄偶性和要删的点相同,就让猫猫移动一次,否则让猫猫移动两次。
(从大到小删是为了保证删掉这个点后,猫猫一定和主线联通)
处理主线的方式同理
好简单的 1900,分析一下奇偶性就没了
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
vector<vector<int>> g(n+1);
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> fa(n+1),dep(n+1),st(n+1);
auto dfs=[&](auto dfs,int u,int pre)->void {
fa[u]=pre;
dep[u]=dep[pre]+1;
for(auto v:g[u]){
if(v==pre) continue;
dfs(dfs,v,u);
}
};
dfs(dfs,1,0);
vector<pii> t;
vector<pii> ans;
int now=n;
while(fa[now]){
st[now]=1;
now=fa[now];
}
for(int i=1;i<=n;i++){
if(!st[i]){
t.push_back({dep[i],i});
}
}
now=1;
sort(t.begin(),t.end());
//删掉所有支线
while(t.size()){
auto [dp,u]=t.back();
if(now==(dp&1)){
ans.push_back({1,0});
now^=1;
}
else{
ans.push_back({1,0});
ans.push_back({1,0});
}
ans.push_back({2,u});
t.pop_back();
}
for(int i=1;i<=n;i++){
if(st[i]){
t.push_back({dep[i],i});
}
}
sort(t.begin(),t.end(),greater<pii>());
while(t.size()>1){
auto [dp,u]=t.back();
if(now==(dp&1)){
ans.push_back({1,0});
now^=1;
}
else{
ans.push_back({1,0});
ans.push_back({1,0});
}
ans.push_back({2,u});
t.pop_back();
}
cout<<ans.size()<<endl;
for(auto [a,b]:ans){
if(b) cout<<a<<" "<<b<<endl;
else cout<<a<<endl;
}
cout<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
}
D. Division Versus Addition
Squarepoint Challenge (Codeforces Round 1055, Div. 1 + Div. 2)
https://codeforces.com/problemset/problem/2152/D
对于所有的数,计算出每次先 +1 再 /2 和先 /2 再 +1,两种情况的操作次数
如果某个数两种方式的操作次数一样,则不重要,否则重要
对于两个人的操作,显然是要抢所有重要的数,的第一次操作
设有 \(k\) 个重要的数,则第一个人可以抢得到 \((k+1)/2\) 个数的第一次
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n,q;
cin>>n>>q;
vector<int> a(n+1),b(n+1),c(n+1),d(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
int val=a[i];
while(val>1){
val++;
val>>=1;
b[i]++;
}
val=a[i];
while(val>1){
val>>=1;
if(val>1) val++;
c[i]++;
}
d[i]=b[i]-c[i];
d[i]+=d[i-1];
b[i]+=b[i-1];
}
while(q--){
int l,r;
cin>>l>>r;
cout<<b[r]-b[l-1]-(d[r]-d[l-1]+1)/2<<endl;
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
}
D. Not Alone
Codeforces Round 1057 (Div. 2)
https://codeforces.com/problemset/problem/2153/D
相当于把整个序列分成很多段,令每段的元素都相等的最小代价
最优分段方式的段长显然只有 \(2\) 和 \(3\) 就行了,简单 DP 即可
处理环时,可以分别在原数组上处理一次,把 \(a[1]\) 放到最后处理一次,把 \(a[1],a[2]\) 放到最后处理一次
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
auto wk=[&](int idx)-> int {
vector<int> t;
t.push_back(0);
for(int i=idx;i<=n;i++){
t.push_back(a[i]);
}
for(int i=1;i<idx;i++){
t.push_back(a[i]);
}
vector<int> f(n+1,inf);
f[2]=abs(t[1]-t[2]);
f[3]=max({t[1],t[2],t[3]})-min({t[1],t[2],t[3]});
for(int i=4;i<=n;i++){
f[i]=min(f[i-2]+abs(t[i-1]-t[i]),f[i-3]+max({t[i],t[i-1],t[i-2]})-min({t[i],t[i-1],t[i-2]}));
}
return f[n];
};
int ans=inf;
for(int i=1;i<=3;i++){
ans=min(ans,wk(i));
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
}
B. Grid Counting
Codeforces Round 1053 (Div. 1)
https://codeforces.com/problemset/problem/2150/B
为了满足条件二,三,每列必须填一个,而且左右第 \(i\) 列必须在前 \(i\) 行填完
推出,前 \(\lceil n/2 \rceil\) 行必须把 \(n\) 列都填完。
从上往下对每行统计方案数很困难,从下往上组合数学统计方案数即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
/*支持define int long long 的自动取模类*/
template<const int T>
struct ModInt {
const static int mod = T;
int x;
ModInt(signed x = 0) : x(x % mod) {}
ModInt(long long x) : x((int)x % mod) {}
int val() { return x; }
ModInt operator + (const ModInt &a) const { int x0 = x + a.x; return ModInt(x0 < mod ? x0 : x0 - mod); }
ModInt operator - (const ModInt &a) const { int x0 = x - a.x; return ModInt(x0 < 0 ? x0 + mod : x0); }
ModInt operator * (const ModInt &a) const { return ModInt(1LL * x * a.x % mod); }
ModInt operator / (const ModInt &a) const { return *this * a.inv(); }
bool operator == (const ModInt &a) const { return x == a.x; };
bool operator != (const ModInt &a) const { return x != a.x; };
void operator += (const ModInt &a) { x += a.x; if (x >= mod) x -= mod; }
void operator -= (const ModInt &a) { x -= a.x; if (x < 0) x += mod; }
void operator *= (const ModInt &a) { x = 1LL * x * a.x % mod; }
void operator /= (const ModInt &a) { *this = *this / a; }
friend ModInt operator + (int y, const ModInt &a){ int x0 = y + a.x; return ModInt(x0 < mod ? x0 : x0 - mod); }
friend ModInt operator - (int y, const ModInt &a){ int x0 = y - a.x; return ModInt(x0 < 0 ? x0 + mod : x0); }
friend ModInt operator * (int y, const ModInt &a){ return ModInt(1LL * y * a.x % mod);}
friend ModInt operator / (int y, const ModInt &a){ return ModInt(y) / a;}
friend ostream &operator<<(ostream &os, const ModInt &a) { return os << a.x;}
friend istream &operator>>(istream &is, ModInt &t){return is >> t.x;}
ModInt pow(int64_t n) const {
ModInt res(1), mul(x);
while(n){
if (n & 1) res *= mul;
mul *= mul;
n >>= 1;
}
return res;
}
ModInt inv() const {
int a = x, b = mod, u = 1, v = 0;
while (b) {
int t = a / b;
a -= t * b; swap(a, b);
u -= t * v; swap(u, v);
}
if (u < 0) u += mod;
return u;
}
};
using mint = ModInt<mod>;
const int N=2e5+1;
vector<int> fact(N),infact(N);
int qmi(int a,int b,int p){
int res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
void init(){
fact[1]=1;
fact[0]=1;
infact[0]=1;
infact[1]=1;
for(int i=2;i<N;i++){
fact[i]=fact[i-1]*i%mod;
infact[i]=qmi(fact[i],mod-2,mod);
}
}
int C(int a,int b){
if(a<b) return 0;
return fact[a]*infact[b]%mod*infact[a-b]%mod;
}
void solve(){
int n;
cin>>n;
vector<int> a(n+1);
vector<int> nd(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n/2;i++){
nd[i]=2;
}
if(n&1) nd[(n+1)/2]=1;
int now=0;
mint ans=1;
for(int i=n;i>=1;i--){
now+=nd[i];
if(a[i]>now) {
cout<<0<<endl;
return;
}
ans*=C(now,a[i]);
now-=a[i];
}
if(now!=0){
cout<<0<<endl;
return;
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
init();
int ct=1;
cin>>ct;
while(ct--){
solve();
}
}
D. Game on Array
Codeforces Global Round 29 (Div. 1 + Div. 2)
https://codeforces.com/problemset/problem/2147/D
初始时,数值为偶数的值,在双方都使用最优策略时没有影响,所以只考虑初始时值为奇数的数字。
对值为奇数的每个数字各取一次变成偶数,而偶数就是双方均分
所以双方各取一半奇数的第一次即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
map<int,int> mp;
for(int i=1;i<=n;i++){
int val;
cin>>val;
mp[val]++;
}
int a=0,b=0;
vector<int> t;
for(auto [val,cnt]:mp){
a+=cnt*(val/2);
b+=cnt*(val/2);
if(val&1){
t.push_back(cnt);
}
}
sort(t.begin(),t.end(),greater<int>());
for(int i=0;i<t.size();i++){
if(i&1) b+=t[i];
else a+=t[i];
}
cout<<a<<" "<<b<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
}
F. Gravity Falls
Codeforces Round 1050 (Div. 4)
https://codeforces.com/problemset/problem/2148/F
模拟过程即可,假设当前 \(k\) 位已被确定,则可以在此时对所有字符串排序,排序依据是所有字符串 \(k+1\) 位到末尾的字典序,找一个最小值
容易证明,每个字符串的每个字符最多被访问一次
点击查看代码
#include<bits/stdc++.h>
// #define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
vector<vector<int>> a(n+1);
int mxk=0;
for(int i=1;i<=n;i++){
int k;
cin>>k;
mxk=max(k,mxk);
vector<int> t(k+1);
for(int j=1;j<=k;j++){
cin>>t[j];
}
a[i]=t;
}
vector<vector<int>> ans(1);
vector<int> st(n+1);
int idx=1;
auto check=[&](int t1,int t2,int val)-> bool {
auto s1=a[t1];
auto s2=a[t2];
for(int i=val;i<=mxk;i++){
if(s1.size()<=i) return 1;
if(s2.size()<=i) return 0;
if(s1[i]<s2[i]) return 1;
if(s1[i]>s2[i]) return 0;
}
return 1;
};
while(idx<=mxk){
int now=0;
for(int i=1;i<=n;i++){
if(st[i]) continue;
if(a[i].size()-1<idx) continue;
if(now==0) now=i;
else{
if(check(i,now,idx)){
now=i;
}
}
}
ans.push_back(a[now]);
idx=a[now].size();
}
for(int i=1;i<=mxk;i++){
for(int j=1;j<ans.size();j++){
if(ans[j].size()>i){
cout<<ans[j][i]<<' ';
break;
}
}
}
cout<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
}
G. Farmer John's Last Wish
Codeforces Round 1050 (Div. 4)
https://codeforces.com/problemset/problem/2148/G
好妙的题,看明白题解的时候神清气爽
对于新加进来的一个数,两种情况
-
放到最后一个,则前面 \(gcd\) 的所有因数一定有有一个是当前数不存在的。这里直接用 \(gcd\) 算一下就行
-
放到前面,不让当前数作为第 \(k+1\) 个数,则此时可以枚举当前数的所有因数,对于一个因数 \(t\),看看当前序列中有多少个数
-
继承前一个数的答案 \(ans[i]=ans[i-1]\)
-
放到前面,且让当前数作为第 \(k+1\) 个数,但这种情况已经被 \(ans[i-1]\) 覆盖
1187E E. Tree Painting
换根DP。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
vector<vector<int>> g(n+1);
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> sz(n+1);
auto dfs=[&](auto dfs,int u,int pre)-> void {
sz[u]=1;
for(auto v:g[u]){
if(v==pre) continue;
dfs(dfs,v,u);
sz[u]+=sz[v];
}
};
dfs(dfs,1,0);
vector<int> ans(n+1);
auto f=[&](auto f,int u,int pre)-> void {
for(auto v:g[u]){
if(v==pre) continue;
ans[v]=ans[u]-sz[v]+(n-sz[v]);
int pu=sz[u],pv=sz[u];
sz[u]=n-sz[v];
sz[v]=n;
f(f,v,u);
sz[v]=pv,sz[u]=pu;
}
};
for(int i=1;i<=n;i++){
ans[1]+=sz[i];
}
f(f,1,0);
int t=0;
for(int i=1;i<=n;i++){
t=max(t,ans[i]);
}
cout<<t<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}

浙公网安备 33010602011771号