Codeforces 1061 Div2(ABCDF1)
前言
青名还没捂热就没了呜呜呜……
一、A. Pizza Time
#include <bits/stdc++.h>
using namespace std;/* /\_/\
* (= ._.)
* / > \>
*/#define dbg(x) cout<<#x<<" "<<x<<endl
#define vdbg(a) for(auto x:a) cout<<x<<" ";cout<<endl
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;void solve()
{ll n;cin>>n;cout<<(n-3)/2+1<<endl;
}signed main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--){solve(); }return 0;
}
上来猜错了还wa了一次……
因为让第一个人吃的最多就相当于让第二个人吃的最少,那么每次分的时候肯定是给两个人各分一个,再让剩下的去下一轮,那么打个表观察一下就能发现,直接输出(n-3)/2+1即可。
二、B. Strange Machine
太抽象了,想了半天都没想到可以暴力……
#include <bits/stdc++.h>
using namespace std;/* /\_/\
* (= ._.)
* / > \>
*/#define dbg(x) cout<<#x<<" "<<x<<endl
#define vdbg(a) for(auto x:a) cout<<x<<" ";cout<<endl
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;void solve()
{int n,q;cin>>n>>q;string s;cin>>s;s=" "+s;bool ok=true;for(int i=1;i<=n;i++){if(s[i]=='B'){ok=false;break;}}vector<ll>a(q+1);for(int i=1;i<=q;i++){cin>>a[i];}for(int i=1;i<=q;i++){ll x=a[i];if(ok){cout<<x/n*n+x%n<<endl;continue;}ll ans=0;while(x){for(int i=1;i<=n;i++){if(s[i]=='A'){x--;}else{x/=2;}ans++;if(x==0){break;}}}cout<<ans<<endl;}
}signed main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--){solve(); }return 0;
}
感觉脑子一团浆糊,思路一团乱麻……
注意到只要有一个除以2操作,那么每个数执行最多执行logx轮,而若除以2的操作更多,那么即使x是10的9次方级别,也不会执行太多轮操作。所以只需要特判一下全是1的情况,然后其他情况直接暴力模拟即可。
三、C. Maximum GCD on Whiteboard
#include <bits/stdc++.h>
using namespace std;/* /\_/\
* (= ._.)
* / > \>
*/#define dbg(x) cout<<#x<<" "<<x<<endl
#define vdbg(a) for(auto x:a) cout<<x<<" ";cout<<endl
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;void solve()
{int n,k;cin>>n>>k;vector<int>a(n+1);for(int i=1;i<=n;i++){cin>>a[i];}//若想把一个数b分成x的倍数,那么最小的情况就是b=x+x+x,这样显然原本就可以被x整除//那么若3x<b<4x,就只能修改第三位了,所以也不符合条件//若b>4x,若b=kx+d,那么总是可以分成b=x+(x+d)+(k-2)x//所以对于选定的答案x,对于大于4x的数都可以将其拆开vector<int>cnts(4*n+1);for(int i=1;i<=n;i++){cnts[a[i]]++;}vector<int>sums(4*n+1);for(int i=1;i<=4*n;i++){sums[i]=sums[i-1]+cnts[i];}for(int i=n;i>=2;i--){int cur=sums[4*i-1]-sums[3*i]+sums[3*i-1]-sums[2*i]+sums[2*i-1]-sums[i]+sums[i-1];if(cur<=k){cout<<i<<endl;return ;}}cout<<1<<endl;
}signed main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--){solve(); }return 0;
}
这题没观察出来直接寄了……
首先,若想让整个数组的gcd为x,那么就需要把所有非x倍数的数b分裂或消除。首先考虑分裂,若想将b分裂后保留的是x的倍数,最小的情况就是b=x+x+x,但这样显然b就是x的倍数。那么若3x<b<4x,就只能修改分裂后的第三个数了,所以也不符合条件。若b>4x,若b=kx+d,那么永远可以将b分成b=x+(x+d)+(k-2)x,所以只要b大于4x,就可以将其分裂。
所以考虑统计每个数词频的前缀和,然后从大到小枚举gcd,那么对于当前的答案gcd,需要删除的数就是0<b<x,x<b<2x,2x<b<3x和3x<b<4x的数,若小于等于k就直接输出即可。
四、D. Find the Last Number
评价是D<<<<<C……
视频题解:【A~F2】Codeforces Round 1061 (Div. 2) 讲解
#include <bits/stdc++.h>
using namespace std;/* /\_/\
* (= ._.)
* / > \>
*/#define dbg(x) cout<<#x<<" "<<x<<endl
#define vdbg(a) for(auto x:a) cout<<x<<" ";cout<<endl
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;void solve()
{int n;cin>>n;vector<int>cur;for(int i=1;i<n;i++){cur.push_back(i);}vector<int>nums;for(int i=1;i<=n;i++){nums.push_back(i);}int ans=0;for(int i=0;(1<<i)<=n;i++){int cnts=0;for(auto x:nums){if((x>>i)&1){cnts++;}}vector<int>ones;vector<int>zeros;for(auto x:cur){cout<<"? "<<x<<" "<<(1<<i)<<endl;cout<<endl;int res;cin>>res;if(res){ones.push_back(x);}else{zeros.push_back(x);}} vector<int>nnum;cur.clear();if(ones.size()==cnts-1){for(auto x:nums){if((x>>i)&1){nnum.push_back(x);}}nums=nnum;cur=ones;}else{for(auto x:nums){if(!((x>>i)&1)){nnum.push_back(x);}}nums=nnum;cur=zeros;}if(nums.size()==1){cout<<"! "<<nums[0]<<endl;return ;}}
}signed main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--){solve(); }return 0;
}
因为只能回答与的结果是否是0,所以就相当于只能判断该位的状态,所以最暴力的方法就是考虑所有数每一位的状态,那么这样就是得到最后一个位置的数所有位的状态。但由于n是2e4的,所以这肯定就超出2n的限制了。之后观察可以发现,若当前确定了最后一个位置数第i位的状态,那么对于1~n中第i位状态不同的数就都排除了,即答案状态不同的下标以后就都没必要问了,所以每次能减少近一半的数,次数(n-1)+(n-1)/2+(n-1)/4+……,肯定是小于2n的。
六、F1. Strange Operation (Easy Version)
#include <bits/stdc++.h>
using namespace std;/* /\_/\
* (= ._.)
* / > \>
*/#define endl '\n'
#define dbg(x) cout<<#x<<" "<<x<<endl
#define vdbg(a) cout<<#a<<endl; for(auto x:a) cout<<x<<" ";cout<<endl
#define INF 1e9
#define INFLL 1e18
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;void solve()
{int n;cin>>n;vector<int>a(n+1);for(int i=1;i<=n;i++){cin>>a[i];}//因为p[i]每次都减2,所以p[i]的奇偶性不会改变//若首位是奇数,那么考虑优先让其变为1,否则优先让其变为2vector<int>pos(n+1);for(int i=1;i<=n;i++){pos[a[i]]=i;}for(int v=1;v<=n;v++){//当前数值v可以到的最左位置int head=n;//枚举大于等于v的所有数for(int i=v,minn=n;i<=n;i++){//当前数所在位置更小if(pos[i]<minn){minn=pos[i];//两数奇偶性相同if(i%2==v%2){head=pos[i];}}}//最左位置的数int vhead=a[head];//修改a[head]=v;//需要让[v,vhead)的数全部加1for(int i=v;i<vhead;i++){a[pos[i]]++;}//往下移一位 -> 全部加1for(int i=vhead;i>v;i--){pos[i]=pos[i-1];}//修改位置pos[v]=vhead;}for(int i=1;i<=n;i++){cout<<a[i]<<" ";}cout<<endl;
}signed main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--){solve(); }return 0;
}
这题真的抽象,如果观察出来了就能秒……
注意到p[i]位置的数每次减2不会改变其奇偶性,那么贪心得想可以发现,若肯定是让首位的数尽可能小,那么若首位是奇数就让其变成1,偶数就变成2,之后以此类推。之后又注意到,若首位是奇数x,在其减小的过程中,1~x-1的数全会增加1。所以代码上就是需要先记一下每个数出现的位置,然后从1开始枚举,每次找当前数可以到的最左位置,然后让该位置的变成当前数。最后每次都按照上述规律修改数值和位置即可。
总结
感觉身体好点了,加训吧,争取一天vp一场d2!
