为什么一VP就能过这么多…
题目链接
https://codeforces.com/contest/1535
A 题意
四个数,12比34比之后再比。如果决赛是最强的俩人比就是公平,问是否公平
A 思路
最强次强别再第一轮相遇即可
A 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=400505;
const int inf=0x3f3f3f3f;
int n,m,k;
int a[maxn];
void solve(){
int ma=-inf,mi=inf,in1,in2;
for(int i=0;i<4;i++){
int t;
cin>>t;
if(t>ma){
mi=ma,in2=in1;
ma=t,in1=i;
}
else if(t>mi){
mi=t,in2=i;
}
}
if((in1^1)==in2){
cout<<"NO"<<endl;
}
else{
cout<<"YES"<<endl;
}
}
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn=1;
cin>>tn;
while(tn--){
solve();
}
}
B 题意
排序数组,让数对ij满足i<j,gcd(a[i],2a[j])!=1最多。
B 思路
注意那个2a[j]很有意思,我们贪心处理,所有偶数扔最前面,他们和后面gcd一定比>=2,这部分是个等差求和,之后就可以剔除掉它们了。剩下奇数,那么其实gcd(a[i],2a[j])和gcd(a[i],a[j])也就没有区别了,那么排序也就无所谓了,直接两个枚举求就好了。
B 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=400505;
const int inf=0x3f3f3f3f;
int n,m,k;
int a[maxn];
vector<int>v;
int ans;
void solve(){
ans=0;
int t=0,k=0;
v.clear();
cin>>n;
for(int i=1;i<=n;i++){
int w;
cin>>w;
if(w%2){
v.push_back(w);
t++;
}
else{
k++;
}
}
ans=k*(2*t+k-1)/2;
n=v.size();
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
if(__gcd(v[i],v[j])!=1) ans++;
cout<<ans<<endl;
}
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn=1;
cin>>tn;
while(tn--){
solve();
}
}
C 题意
一个unstable串定义为01010101,10101010这种不存在00和11的01串。一个美丽串定义为01?的三元串,且?可以填0或者1使得这个串变成unstable串。问给出的串有几个美丽子串。子串定义为去前缀后缀的原串
C 思路
我们统计每个元素为最左端的情况下子串数量,这样总和就是不重不漏所有子串了。
我们统计每个元素最远能延展的最右端下标,比如0010,第一个0只能延展到2,因为00不合法,第二个0可以延展到5,因为后面全合法。容易发现上文提到的子串数量就是这个新统计量-自己下标。对于?我们暂时跳过,如果是别的元素延展过程中遇到了?,默认其合法,继续延展。统计完后我们把?的统计量设为他右边元素的统计量即可。比如?11,我们先跳过?,2号位置1的统计量是3,3号是4,我们再回头把1号?的统计量设为3.答案就是(4-3)+(3-2)+(3-1)。
对于维护这个统计量,我们线性扫一遍就可以了,我这里用了个比较麻烦的实现,属于是比赛的时候紧张了。一会看看有没有必要重写下。
C 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=400505;
const int inf=0x3f3f3f3f;
int n,m,k;
int a[maxn];
int b[maxn],d[maxn];
vector<int>v;
int ans;
void solve(){
ans=0;
string s;
cin>>s;
n=s.size();
for(int i=0;i<=n;i++) b[i]=d[i]=0;
s='z'+s;
for(int i=1;i<=n;i++){
if(s[i]=='?') continue;
int t=s[i]-'0';
b[i]=(t+i)%2;
}
stack<int>sa;
for(int i=1;i<=n;i++){
if(s[i]=='?') continue;
if(sa.empty()||b[sa.top()]==b[i])
sa.push(i);
else{
while(sa.size()){
int now=sa.top();sa.pop();
d[now]=i;
}
sa.push(i);
}
}
while(sa.size()){
int now=sa.top();sa.pop();
d[now]=n+1;
}
d[n]=n+1;
for(int i=n;i;i--){
if(!d[i])
d[i]=d[i+1];
ans+=d[i]-i;
}
cout<<ans<<endl;
}
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn=1;
cin>>tn;
while(tn--){
solve();
}
}
D 题意
类似A的竞赛,只不过初始队伍变多,有2^(k+1)支队伍,那么也就需要k轮竞赛。给你一个01?串,按坐标代表第i场比赛输赢,0代表小队赢,1代表大队赢,?代表都可能。f(s)意为在s情况下有几个队有机会赢,q次询问改变s某一位,每次操作完输出f(s)
D 思路
k才18,几十万的数量级,我们直接dp[I]代表i场比赛能产生几个胜者。x,y代表产生i比赛的两个前置比赛,有
d
p
(
i
)
=
{
d
p
(
x
)
,
s
[
i
]
=
0
d
p
(
y
)
,
s
[
i
]
=
1
d
p
(
x
)
+
d
p
(
y
)
,
s
[
i
]
=
?
dp(i)=\left\{ \begin{aligned} dp(x),s[i]=0\\ dp(y),s[i]=1\\ dp(x)+dp(y),s[i]=? \end{aligned} \right.
dp(i)=⎩⎪⎨⎪⎧dp(x),s[i]=0dp(y),s[i]=1dp(x)+dp(y),s[i]=?
推一下由i找到xy和由xy找到i的公式,每次修改改掉s[i]之后暴力传递一下即可,复杂度应该是qk的。
D 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=1000505;
const int inf=0x3f3f3f3f;
int n,m,k;
int dp[maxn];
string s;
int t,fi;
inline int s1(int x){
return max(2*(x-1-t)+1,0ll);
}
inline int s2(int x){
return max(2*(x-1-t)+2,0ll);
}
inline int fa(int x){
return (x+1)/2+t;
}
void up(int x){
if(x>fi) return ;
if(s[x]=='?'){
dp[x]=dp[s1(x)]+dp[s2(x)];
}
else if(s[x]=='0'){
dp[x]=dp[s1(x)];
}
else
dp[x]=dp[s2(x)];
up(fa(x));
}
void change(int x,char c){
if(s[x]==c)
return ;
s[x]=c;
up(x);
}
void solve(){
for(int i=0;i<maxn;i++) dp[i]=1;
cin>>k;
t=pow(2,k-1);
fi=pow(2,k)-1;
cin>>s;
s='z'+s;
for(int i=1;i<=fi;i++){
if(s[i]=='?')
up(i);
}
//for(int i=1;i<=t;i++)
// up(i);
cin>>m;
while(m--){
int a;
char b;
cin>>a>>b;
change(a,b);
cout<<dp[fi]<<endl;
}
}
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn=1;
while(tn--){
solve();
}
}
E 题意
给你一颗树,初始只有根。每个点有a,c两个值,代表这个点有多少金子,每吨多少钱。给出q个操作如下
- 插入一个新结点,满足新节点金价在所有父节点中最贵
- 给出结点号和需求量,在根到这个结点中买金子,问最多能买多少,花多少钱。要求花的钱最少。
E 思路
注意子节点金子更贵。所以我们策略一定是优先买根节点近的金子,在链上操作,我们直接搞一个倍增找还有金子的父节点,能买就全买,直到买完或者买完当前节点都不够为止。
第一道树上倍增,有点意思,一会学学。
E 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=400505;
const int inf=0x3f3f3f3f;
int n,m,k,q;
int arr[maxn];
int cost[maxn],have[maxn];
int fa[maxn][25];
int get(int x){
for(int i=24;~i;i--){
if(fa[x][i]&& have[fa[x][i]]) x=fa[x][i];
}
return x;
}
void solve(){
cin>>q>>have[1]>>cost[1];
for(int i=2;i<=q+1;i++){
int op,a,b,c,d;
cin>>op;
if(op==1){
cin>>a>>b>>c;
a++;
have[i]=b,cost[i]=c;
fa[i][0]=a;
for(int j=1;j<25;j++)
fa[i][j]=fa[fa[i][j-1]][j-1];
}
else{
cin>>a>>b;//a到0买b吨
a++;
int cc=0,hh=0;
while(1){
int x=get(a);
if(!have[x]) break;
int can_buy=min(b,have[x]);
hh+=can_buy;
have[x]-=can_buy;
cc+=cost[x]*can_buy;
b-=can_buy;
if(!b||x==a) break;//买够了,或者把自己都买空了。
}
cout<<hh<<' '<<cc<<endl;
cout.flush();
}
}
}
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
int tn=1;
while(tn--){
solve();
}
}