Codeforces Round #737 (Div. 2)
场上b看错题面卡到失智,开了个d又把题面看反以为是选择的01串不能有共同的1列,车了个网络流赛后才反应过来,只能说还好c正常切出来了。。。全麻
1 s,256 mb
给你n个数,分成2组,最大化两组平均数之和。
把最大数单拉出来就行了
#include<iostream>
#include<algorithm>
#include<string.h>
#include<utility>
#include<vector>
#include<queue>
//#include<cmath>
//#include<math.h>
#include<stack>
#include<map>
//#include<cmath>
#include<cstdlib>
#include<bitset>
using namespace std;
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define ii pair<int,int>
//#define maxn 2400000
#define SZ(x) x.size()
#define INF (1<<29)
#define mod 1000000007
#define pb push_back
#define mp make_pair
#define maxb 1010
#define sc(x) scanf("%d",&x)
#define mes(x) memset(x.0.sizeof(x))
#define mod 1000000007
#define maxn 200010
#define N 510
#define Q 500010
int read()
{
int num=0; char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar(); //过滤前面非数字字符
while(ch>='0'&&ch<='9') {num*=10;num+=ch-'0';ch=getchar();}
return num;
}
LL read1()
{
LL num=0; char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar(); //过滤前面非数字字符
while(ch>='0'&&ch<='9') {num*=10;num+=ch-'0';ch=getchar();}
return num;
}
int T,n;
LL x;
int main(){
cin>>T;
while(T--){
cin>>n;
LL sum=0;
LL ansn=-2000000000;
FOR(i,1,n) {
cin>>x;
ansn=max(ansn,x);
sum+=x;
}
long double ans=ansn+(long double) (sum-ansn)/(long double)(n-1);
printf("%Lf\n",ans);
}
}
2 s,256 mb
给你个长度为n序列,问是否可能将其分为k个互不相交的子序列,按任意顺序合并后变为原序列的升序表示,保证序列中不存在两两相同的数。
经过分割的序列其内部的顺序是不变的,如果能合并成升序表示,那么分割序列本身就是升序表示的。
排序后O(n)扫一遍,能够获知所有必须进行分割的点的个数,等价于去找到达成条件最少需要分割的序列数cnt
分割好的升序子序列取头和尾任一端即可再分裂出由单个元素构成的升序子序列
故cnt<=k时有解,否则无解
#include<iostream>
#include<algorithm>
#include<string.h>
#include<utility>
#include<vector>
#include<queue>
//#include<pair>
//#include<cmath>
//#include<math.h>
#include<stack>
#include<map>
//#include<cmath>
#include<cstdlib>
#include<bitset>
using namespace std;
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define ii pair<int,int>
//#define maxn 2400000
#define SZ(x) x.size()
#define INF (1<<29)
#define mod 1000000007
#define pb push_back
#define mp make_pair
#define maxb 1010
#define sc(x) scanf("%d",&x)
#define mes(x) memset(x.0.sizeof(x))
#define mod 1000000007
#define maxn 200010
#define N 510
#define Q 500010
int read()
{
int num=0; char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar(); //过滤前面非数字字符
while(ch>='0'&&ch<='9') {num*=10;num+=ch-'0';ch=getchar();}
return num;
}
LL read1()
{
LL num=0; char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar(); //过滤前面非数字字符
while(ch>='0'&&ch<='9') {num*=10;num+=ch-'0';ch=getchar();}
return num;
}
int T,n,k;
int a[100010];
pair<int,int> b[100010];
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);
FOR(i,1,n){scanf("%d",&a[i]);b[i]={a[i],i};}
sort(b+1,b+n+1);
int sum=1;
FOR(i,1,n-1){
if(b[i].second+1!=b[i+1].second) sum++;
}
if(sum<=k) cout<<"YES"<<endl; else cout<<"NO"<<endl;
}
}
2 s,256 mb
求长度恰好为n的Ai序列个数,要求满足0<Ai<2^k-1,&1~nAi>=XOR1~nAi
独立看某一位,计算出>,=,<成立的方案数cnt1,cnt2,cnt3
如果&1~nAi>=XOR1~nAi左边大于等于右边,那么一定是从某一位开始左边不等于右边而是大于右边,而之后的所有位都是自由选取的
则ans=∑j=(n-1)~0cnt2j cnt1 (2k)n-j-1+cnt2n
n为偶数时cnt1=0,奇数时为0,分情况化简即可
#include<iostream>
#include<algorithm>
#include<string.h>
#include<utility>
#include<vector>
#include<queue>
//#include<pair>
//#include<cmath>
//#include<math.h>
#include<stack>
#include<map>
//#include<cmath>
#include<cstdlib>
#include<bitset>
using namespace std;
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define ii pair<int,int>
//#define maxn 2400000
#define SZ(x) x.size()
#define INF (1<<29)
#define mod 1000000007
#define pb push_back
#define mp make_pair
#define maxb 1010
#define sc(x) scanf("%d",&x)
#define mes(x) memset(x.0.sizeof(x))
#define mod 1000000007
#define maxn 200010
#define N 510
#define Q 500010
int read()
{
int num=0; char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar(); //过滤前面非数字字符
while(ch>='0'&&ch<='9') {num*=10;num+=ch-'0';ch=getchar();}
return num;
}
LL read1()
{
LL num=0; char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar(); //过滤前面非数字字符
while(ch>='0'&&ch<='9') {num*=10;num+=ch-'0';ch=getchar();}
return num;
}
int T,n,k;
LL qpow(int x,int k){
LL ans=1;
LL a=x;
while(k){
if(k&1) ans=(ans*a)%mod;
a=(a*a)%mod;k>>=1;
}
return ans;
}
LL a[200010],b[200010];
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);
LL cnt=qpow(2,n-1);
LL cnt2=qpow(2,n);
LL kk=0;
if(n&1) cnt--;else kk=1;
LL cnt3=cnt2-cnt;
//if(!(n&1)) kk=1;
cnt3=(cnt3-kk+mod+mod)%mod;
//cout<<cnt3<<endl;
//cnt3 =
//k >
//cnt2 tot
a[0]=1;
FOR(i,1,k) a[i]=(a[i-1]*cnt3)%mod;
b[0]=1;
FOR(i,1,k) b[i]=(b[i-1]*cnt2)%mod;
LL ans=a[k];
if(kk==0) cout<<ans<<endl;
else{
FOR(i,0,k-1){
ans=(ans+(a[i]*b[k-1-i]))%mod;
}
cout<<ans<<endl;
}
}
}
2.5 s,256 mb
给n行01串,要求你移除若干行,使得余下的所有相邻行两两都至少有1列都为1
反过来想,变成选最多行使得条件满足,显然如果我们选了第j行,之前选的其他行都不会对之后的决策产生影响
我们定义i行可以转移到j行的条件为i<j且i,j至少有一列都为1
那么问题就转化为找n个点的DAG上的最长转移路径,显然dp[i]=max(dp[j])+1 j<i,ij具有公共1列
n=3e5,t=2.5s,我们需要确保每次转移的均摊常数在1e3左右
建转移图是没戏了,n2再见。
但是我们可以维护每个公共1列的转移点的最优决策,很容易想到用线段树维护(显然根号级别维护会被花式叉),
如果选当前列就对于自己包含1的列查询之前最后一次选这列的备选答案,取最优值,显然这个单点询问可以变成区间询问。
更新完答案回头在线段树上再刷一遍即可
含1区间离散化最多6e5个端点,转移+更新2log也就是60多的常数,大常数选手点了个赞。
#include<iostream>
#include<algorithm>
#include<string.h>
#include<utility>
#include<vector>
#include<queue>
#include<cmath>
#include<math.h>
#include<stack>
#include<map>
#include<set>
#include<cstdlib>
#include<bitset>
using namespace std;
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define FORD(i,j,k) for(int i=j;i>=k;i--)
#define LL long long
#define ii pair<int,int>
//#define maxn 2400000
#define SZ(x) x.size()
#define INF (1<<29)
#define pb push_back
#define mp make_pair
#define maxb 1010
#define sc(x) scanf("%d",&x)
#define mes(x) memset(x.0.sizeof(x))
#define mod 1000000007
#define maxn 600010
#define N 510
#define Q 500010
template<class T> bool chkmax(T& a,const T& b){return a<b?a=b,1:0;}
int read()
{
int num=0; char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar(); //过滤前面非数字字符
while(ch>='0'&&ch<='9') {num*=10;num+=ch-'0';ch=getchar();}
return num;
}
LL read1()
{
LL num=0; char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar(); //过滤前面非数字字符
while(ch>='0'&&ch<='9') {num*=10;num+=ch-'0';ch=getchar();}
return num;
}
int T,n,m,k;
const int sz_seg=131072*4*2;
ii sum[sz_seg<<2],lazy[sz_seg<<2];
ii dp[300010];
void pushdown(int cnt,int l,int r){
chkmax(sum[cnt],lazy[cnt]);
if(l!=r) {
int lc=cnt<<1;int rc=cnt<<1|1;
chkmax(lazy[lc],lazy[cnt]);chkmax(lazy[rc],lazy[cnt]);
}
lazy[cnt]={0,0};
}
void pushup(int cnt){
sum[cnt]=max(sum[cnt<<1],sum[cnt<<1|1]);
return;
}
ii query(int ql,int qr,int cnt=1,int l=0,int r=sz_seg-1){
pushdown(cnt,l,r);
if(ql<=l&&r<=qr) return sum[cnt];
if(r<ql||l>qr) return {0,0};
int mid=(l+r)>>1;
return max(query(ql,qr,cnt<<1,l,mid),query(ql,qr,cnt<<1|1,mid+1,r));
}
void adde(int cl,int cr,ii cc,int cnt=1,int l=0,int r=sz_seg-1){
if(cl<=l&&r<=cr){chkmax(lazy[cnt],cc);pushdown(cnt,l,r);return;}
if(cr<l||r<cl) return;
int mid=(l+r)>>1;
pushdown(cnt,l,r);
adde(cl,cr,cc,cnt<<1,l,mid);
adde(cl,cr,cc,cnt<<1|1,mid+1,r);
pushup(cnt);
}
vector<ii> S[300010];
int x,y,z;
int main(){
FOR(i,1,2*sz_seg)sum[i]={0,0},lazy[i]={0,0};
n=read();m=read();
FOR(i,1,m){
x=read();y=read();z=read();
S[x].pb({y,z});
}
set<int> idx;
FOR(i,1,n) for(auto now:S[i]) idx.insert(now.first),idx.insert(now.second);
map<int,int> id;
int tot=0;
for(auto now:idx) id[now]=tot++;
FOR(i,1,n) for(auto& now:S[i]) now.first=id[now.first],now.second=id[now.second];
S[n+1].pb({0,tot-1});
FOR(i,1,n+1){
ii nowans={0,0};
for(auto now:S[i]) chkmax(nowans,query(now.first,now.second));
nowans.first++;dp[i]=nowans;
nowans.second=i;
for(auto now:S[i]) {adde(now.first,now.second,nowans);}
}
cout<<n+1-dp[n+1].first<<endl;
int now=n+1,pre;
while(now!=0){
pre=dp[now].second;
FOR(i,pre+1,now-1) cout<<i<<' ';
now=pre;
}
return 0;
}
E 要补的时候tutorial没了,看了眼好像是说因为A的结论证明不是这题的所以block了。。。麻


浙公网安备 33010602011771号