C. Digital Logarithm
使用优先队列模拟这个元素消去的过程。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+5;
const int inf=1e18;
const int mod=1e9+7;
int fac[40];
int qpow(int a,int b){
int res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int getinv(int x){return qpow(x,mod-2);}
int C(int a,int b)
{
return (fac[a]*getinv(fac[a-b])%mod)*getinv(fac[b])%mod;
}
int n;
priority_queue<int>a,b;
void solve()
{
cin>>n;
for(int i=1;i<=n;i++){
int x;cin>>x;
a.push(x);
}
for(int i=1;i<=n;i++){
int x;cin>>x;
b.push(x);
}
int ans=0;
while(!a.empty()&&!b.empty())
{
int x=a.top();
int y=b.top();
if(x==y)
{
a.pop();b.pop();continue;
}
ans++;
if(x>y)
{
a.pop();
a.push(to_string(x).length());
}
else
{
b.pop();
b.push(to_string(y).length());
}
}
cout<<ans<<endl;
}
signed main()
{
//ios;
int T;cin>>T;
while(T--)
solve();
return 0;
}
G. Good Key, Bad Key
假设两个箱子x和y:
先好钥匙开x再坏钥匙开y:x-k+y/2
先坏要是开x再好钥匙开y: x/2+y/2-k
因此可发现坏要是后面不能接好钥匙,只能接坏钥匙。
暴力求解从何处开始只开坏箱子。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+5;
const int inf=1e18;
const int mod=1e9+7;
int fac[40];
int qpow(int a,int b){
int res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int getinv(int x){return qpow(x,mod-2);}
int C(int a,int b)
{
return (fac[a]*getinv(fac[a-b])%mod)*getinv(fac[b])%mod;
}
int n,k,a[N];
void solve()
{
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
int ans=0,sum=0;
for(int i=1;i<=n;i++)
{
int tp=sum;
for(int j=i;j<=min(i+32,n);j++)
{
int g=a[j];
g>>=j-i+1;
tp+=g;
}
ans=max(ans,tp);
sum+=a[i]-k;
}
ans=max(ans,sum);
cout<<ans<<endl;
}
signed main()
{
//ios;
int T;cin>>T;
while(T--)
solve();
return 0;
}
C. Infected Tree
简单树形dp,没写出来不应该。
状态转移方程:f[x]=max(f[x],f[y]+sz[x]-sz[y]-2);
删除一个分支节点,需要减去2(结点本身和子结点),加上被感染结点最多可保留的符合条件的节点数
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+5;
const int inf=1e18;
const int mod=1e9+7;
int fac[40];
int qpow(int a,int b){
int res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int getinv(int x){return qpow(x,mod-2);}
int C(int a,int b)
{
return (fac[a]*getinv(fac[a-b])%mod)*getinv(fac[b])%mod;
}
int n,ans,sz[N],f[N];
bool vis[N];
vector<int>e[N];
bool cmp(int a,int b){return a>b;}
void dfs(int x,int pre)
{
sz[x]=1;
for(int y:e[x])
{
if(y==pre) continue;
dfs(y,x);
sz[x]+=sz[y];
}
for(int y:e[x])
{
if(y==pre) continue;
f[x]=max(f[x],f[y]+sz[x]-sz[y]-2);
}
for(int y:e[x])
{
if((pre==0&&e[x].size()==1)||(pre!=0&&e[x].size()==2))
f[x]=max(f[x],sz[x]-2);
}
}
void solve()
{
cin>>n;
for(int i=0;i<=n;i++)
sz[i]=f[i]=0,e[i].clear();
for(int i=1;i<n;i++)
{
int u,v;cin>>u>>v;
e[u].push_back(v);e[v].push_back(u);
}
dfs(1,0);
cout<<f[1]<<endl;
}
signed main()
{
ios;
int T;cin>>T;
while(T--)
solve();
return 0;
}
C. Binary String
题意:在一个01字符串中,可从左右两端删除任意的字符,删除1的数目和字符串中0的数目去最大值,要求让这个最大值最小
思路:
s1表示任意字符串的长度,t1字符串中1的数目,t0表示任意字符串中1的数目
不细说了,最后可化简为s1-t1=t0,及求出字符’0‘的前缀和,保证这个差值最大即可,区间长度为1的数目。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+5;
const int inf=1e18;
const int mod=1e9+7;
int fac[40];
int qpow(int a,int b){
int res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int getinv(int x){return qpow(x,mod-2);}
int C(int a,int b)
{
return (fac[a]*getinv(fac[a-b])%mod)*getinv(fac[b])%mod;
}
bool cmp(int a,int b){return a>b;}
int n,ans,sum[N];
bool vis[N];
vector<int>e[N];
void solve()
{
string s;cin>>s;
int g=count(s.begin(),s.end(),'1'),n=s.length();
s=" "+s;
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+(s[i]=='0');
}
int ans=g;
for(int i=g;i<=n;i++)
ans=min(ans,sum[i]-sum[i-g]);
cout<<ans<<endl;
}
signed main()
{
//ios;
int T;cin>>T;
while(T--)
solve();
return 0;
}
A. The Enchanted Forest
感谢队友对于本题数学公式的解释,妙啊
思路:
容易看出分为k<=n和k>n两种情况,每种情况都要考虑增加蘑菇;前者为k*(k-1)/2,后者由于肯定会经过这n个点,因此不妨走到一端后,变保持自己的位置不动,(保持不动我是真的没想到),但是蘑菇数还是再增加的,当实践还剩k-n秒时,我们就要去收割那些本来就有的蘑菇和长处的蘑菇了,此时租箱另一端,在这个过程中,本来保持不懂的端点长出了n个蘑菇踩不到,相邻的一个点有n-1个蘑菇踩不到……以此类推,总数为n*(n+1)/2个蘑菇踩不到。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+5;
const int inf=1e18;
const int mod=1e9+7;
int fac[40];
int qpow(int a,int b){
int res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int getinv(int x){return qpow(x,mod-2);}
int C(int a,int b)
{
return (fac[a]*getinv(fac[a-b])%mod)*getinv(fac[b])%mod;
}
bool cmp(int a,int b){return a>b;}
int n,k,ans,sum[N],a[N];
bool vis[N];
vector<int>e[N];
void solve()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=sum[i-1]+a[i];
}
int ans=0;
if(k<=n)
{
for(int i=k;i<=n;i++)
ans=max(ans,sum[i]-sum[i-k]+k*(k-1)/2);
}
else
ans=sum[n]+k*n-n*(n+1)/2;
cout<<ans<<endl;
}
signed main()
{
//ios;
int T;cin>>T;
while(T--)
solve();
return 0;
}