A.首先题目意思就是看谁拥有的按钮多,所以优先按c的按钮,按两次c等于没按,所以最后看c的奇偶,奇数代表第一个人能多拥有一个,最后判断第一个人和第二个人拥有的总数即可
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+10,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
int n,m,k;
void solve(){
int a,b,c;cin>>a>>b>>c;
a+=c%2;
if(a>b) cout<<"First\n";
else cout<<"Second\n";
}
signed main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
}
B.枚举删除的是那个商店
因为a[i]点一定会吃蛋糕,所以我们只需要计算a[i]-1-a[i-1]的距离需要吃多少蛋糕即可
因为我们插入一个1和n+1
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+10,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
int n,m,k,d;
int a[N];
void solve(){
cin>>n>>m>>d;
for(int i=1;i<=m;i++) cin>>a[i];
a[0]=1;a[m+1]=n+1;
int s=1;
for(int i=1;i<=m+1;i++)
{
s+=(a[i]-a[i-1]-1)/d;
if(i!=m+1&&a[i]!=1)
s++;
}
int res=2e18,cnt=0;
for(int i=1;i<=m;i++)
{
int sum=s;
sum-=(a[i]-a[i-1]-1)/d+(a[i+1]-a[i]-1)/d;
sum+=(a[i+1]-a[i-1]-1)/d;
if(a[i]!=1) sum--;
if(res>sum) res=sum,cnt=1;
else if(res==sum) cnt++;
}
cout<<res<<" "<<cnt<<"\n";
}
signed main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
}
C.
首先构造题无脑打表
额其实好像看不出来啥,但是有个提示
比如排列 1 2 3 6 4 8 57可以换成
1 2 4 8 3 6 5 7
可以观察到 2>4>8>16>32=gcd(2,4,8,16,gcd(32,2))且不会得到重复的gcd
所以大概思路就是每次以某个质因子为起点*2,直到>n
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+10,mod=1e9+7;
typedef long long LL;
typedef pair<int, int> PII;
int n,m,k,d;
void solve(){
cin>>n;
vector<int> st(n+10,false);
st[1]=1;
for(int i=1;i<=n;i++){
if(i==1) cout<<1<<" ";
else{
if(st[i]) continue;
int x=i;
while(x<=n){
cout<<x<<" ";
st[x]=true;
x*=2;
}
}
}
cout<<"\n";
}
signed main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
}
D.首先最长的连续0和连续1肯定不会相交
所有要么0在前,1在后,要么0后1前
所以大概思路就是预处理出
前i颗树,用了j次,0和1的最长前缀连续长度
和后i棵树用了j次,0和1的最长后缀连续长度
然后直接枚举l0为0到n的个数,此时答案就是
max(a*l0前缀个数+l1后缀的个数,a*I0后缀个数+I1前缀个数)
解释一下方程
dp1:前i个树,用了j次,且以i结尾的最长连续长度
如果s[i]==s[i-1]
dp1[i][j]=max(dp1[i][j],dp1[i-1][j]+1)
else:dp1[i][j]=max(dp1[i][j],dp1[i-1][j-1]+1)(j-1>=0)
f:前i个树用了j次的最长前缀长度
以1到i结尾的最长连续长度(dp1[1][j]到dp1[i][j])的最大值
g:后i个树用了j次的最长后缀长度
同上同理
t就是代表当前是I0的长度还是I1的长度
最后统计一下l0从1到n里面 I1最大值即可
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+10,mod=1e9+7;
typedef long long LL;
typedef pair<int, int> PII;
int n,m,k,d;
void solve(){
cin>>n>>k;
string s;cin>>s;
vector<vector<array<int,2>>> f(n+1,vector<array<int,2>>(k+1));
vector<vector<array<int,2>>> g(n+1,vector<array<int,2>>(k+1));
auto get = [&](vector<vector<array<int, 2> > > &dp)
{
vector<vector<array<int,2>>> dp1(n+1,vector<array<int,2>>(k+1));
for(int i = 0; i <n; i++){
for(int j = 0; j <= k; j++){
for(int t = 0; t < 2; t++)
{
dp[i+1][j][t]=max(dp[i+1][j][t],dp[i][j][t]);
if(s[i]-'0'==t)
{
dp1[i + 1][j ][t] = max(dp1[i + 1][j ][t], dp1[i][j][t] + 1);
dp[i+1][j][t]=max(dp[i+1][j][t],dp1[i+1][j][t]);
}
else
{
if(j+1<=k)
{
dp1[i + 1][j + 1][t] = max(dp1[i + 1][j + 1][t], dp1[i][j][t] + 1);
dp[i+1][j+1][t]=max(dp[i+1][j+1][t],dp1[i+1][j+1][t]);
}
}
}
}
}
};
get(f);
reverse(s.begin(),s.end());
get(g);
vector<int> suf(n+10,-2e9);
vector<bool> st(n+10,false);
for(int i=1;i<=n;i++){
for(int j=0;j<=k;j++){
for(int t=0;t<2;t++)
{
int mx1=f[i][j][t];
int mx2=g[n-i][k-j][t^1];
if(t) swap(mx1,mx2);
st[mx1]=true;
suf[mx1]=max(suf[mx1],mx2);
}
}
}
for(int i=n;i>=0;i--)
suf[i]=max(suf[i+1],suf[i]);
vector<int> res(n+1,0);
for(int i=0;i<=n;i++)
{
if(!st[i]) continue;
for(int j=1;j<=n;j++)
{
res[j]=max(res[j],j*i+suf[i]);
}
}
for(int i=1;i<=n;i++)
cout<<res[i]<<" \n"[i==n];
}
signed main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
}
E.给定一个序列
添加一个数相当于上个点和当前点链接一条边,添加一个点
-k就是往上跳k步(可以用倍增处理)
回滚(跳到上一次的点,记录一下上一次到达的点即可)
?(从根节点到当前节点的不同数的个数)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod=1e9+7;
typedef long long LL;
typedef pair<int, int> PII;
int n,m,k,d;
vector<int> g[N],query[N];
int fa[20][N];
int ans[N],a[N],cnt[N],sum;
void dfs(int u){
if (u != 1)
{
if (++cnt[a[u]] == 1)
{
sum += 1;
}
}
for(auto x : query[u]) ans[x] = sum;
for(auto j : g[u]) dfs(j);
if (u != 1){
if (--cnt[a[u]] == 0){
sum -= 1;
}
}
}
void solve(){
cin >> n;
int tot = 1, cur = 1, qs = 0;
vector<int> ops;
ops.reserve(n);
ops.push_back(cur);
for(int i = 0; i < n; i++){
char op;
cin >> op;
if (op == '+'){
int x;
cin >> x;
a[++tot] = x;
fa[0][tot] = cur;
for(int j = 1; j <= 19; j++)
fa[j][tot] = fa[j - 1][fa[j - 1][tot]];
g[cur].push_back(tot);
cur = tot;
ops.push_back(cur);
}
else if (op == '-')
{
int k;
cin >> k;
for(int j = 19; j >= 0; j--){
if (k >> j & 1){
cur = fa[j][cur];
}
}
ops.push_back(cur);
}
else if (op == '!')
{
ops.pop_back();
cur = ops.back();
}
else{
query[cur].push_back(++qs);
}
}
dfs(1);
for(int i = 1; i <= qs; i++)
cout << ans[i] << '\n';
}
signed main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
// cin>>t;
while(t--) solve();
}