Educational Codeforces Round 66 (Rated for Div. 2)

  A:顯然能除就除。c++

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int t;
ll a,b;
signed main()
{
	t=read();
	while (t--)
	{
		cin>>a>>b;
		ll ans=0;
		while (a)
		{
			ans+=a%b;a-=a%b;
			if (a==0) break;a/=b;ans++;
		}
		cout<<ans<<endl;
	}
	return 0;
	//NOTICE LONG LONG!!!!!
}

  B:棧維護。spa

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000000010ll
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int T,stk[100010],top;ll mul[100010],ans;
signed main()
{
	T=read();mul[0]=1;
	while (T--)
	{
		char c=getc();getc(),getc();
		if (c=='a')
		{
			ans+=mul[top];if (ans>=4294967296ll) break;
		}
		if (c=='f')
		{
			stk[++top]=read();mul[top]=min(inf,mul[top-1]*stk[top]);
		}
		if (c=='e')
		{
			top--;
		}
	}
	if (ans>=4294967296ll) cout<<"OVERFLOW!!!";
	else cout<<ans;
	return 0;
	//NOTICE LONG LONG!!!!!
}

  C:枚舉每一個長度爲k的子段取兩端點距離/2(向上取整)更新答案便可。由於顯然對於一個固定點,要找k個點使得離它的最遠點最近,必定是k個點連成一個子段最優。因而能夠反過來對每一個子段求最優勢。blog

 #include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 200010 
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int T,n,k,a[N];
signed main()
{
	T=read();
	while (T--)
	{
		n=read(),k=read();
		for (int i=1;i<=n;i++) a[i]=read();
		int u=inf,pos=0;
		for (int i=1;i<=n;i++)
		if (i+k<=n)
		{
			u=min(u,a[i+k]-a[i]+1>>1);
			if ((a[i+k]-a[i]+1>>1)==u) pos=a[i+k]+a[i]>>1;
		}
		printf("%d\n",pos);
	}
	return 0;
	//NOTICE LONG LONG!!!!!
}

  D:將後綴和排序,取整個序列及除此以外最優的k-1個後綴。排序

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 300010 
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,m;
ll a[N],ans;
signed main()
{
	n=read(),m=read();
	for (int i=1;i<=n;i++) a[i]=read();
	for (int i=n;i>=1;i--) a[i]+=a[i+1];
	sort(a+2,a+n+1);ans+=a[1];m--;
	for (int i=n;i>=n-m+1;i--) ans+=a[i];
	cout<<ans;
	return 0;
	//NOTICE LONG LONG!!!!!
}

 

  E:對每一個點求出包含它的區間的右端點最右是哪一個。而後倍增求出跳2k個區間後能到哪。查詢時從l往r跳便可。ci

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 200010 
#define M 500010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,m,nxt[M][21],mx[M<<2];
struct data{int l,r;
}a[N];
void cover(int k,int l,int r,int x,int y,int p)
{
	if (l==x&&r==y) {mx[k]=max(mx[k],p);return;}
	int mid=l+r>>1;
	if (y<=mid) cover(k<<1,l,mid,x,y,p);
	else if (x>mid) cover(k<<1|1,mid+1,r,x,y,p);
	else cover(k<<1,l,mid,x,mid,p),cover(k<<1|1,mid+1,r,mid+1,y,p);
}
void down(int k,int l,int r)
{
	mx[k]=max(mx[k],mx[k>>1]);
	if (l==r) {nxt[l][0]=mx[k];return;}
	int mid=l+r>>1;
	down(k<<1,l,mid);down(k<<1|1,mid+1,r);
}
signed main()
{
	n=read(),m=read();memset(mx,255,sizeof(mx));memset(nxt,255,sizeof(nxt));
	for (int i=1;i<=n;i++)
	{
		a[i].l=read(),a[i].r=read();
		cover(1,0,500000,a[i].l,a[i].r,a[i].r);
	}
	down(1,0,500000);
	for (int j=1;j<=20;j++)
		for (int i=0;i<=500000;i++)
		if (nxt[i][j-1]!=-1) nxt[i][j]=nxt[nxt[i][j-1]][j-1];
	for (int i=1;i<=m;i++)
	{
		int l=read(),r=read();
		if (nxt[l][20]<r) printf("-1\n");
		else
		{
			int ans=0;
			for (int j=20;~j;j--)
			if (nxt[l][j]<r) ans+=1<<j,l=nxt[l][j];
			printf("%d\n",ans+1);
		}
	}
	return 0;
	//NOTICE LONG LONG!!!!!
}

  F:根據最大值分治,而後只須要考慮跨過最大值且長度等於最大值的值的區間。容易判斷一個區間內是否有相同的數,因而直接暴力就好。get

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 300010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,a[N],f[N][20],nxt[N],p[N],lg2[N],ans;
int query(int x,int y)
{
	return a[f[x][lg2[y-x+1]]]>a[f[y-(1<<lg2[y-x+1])+1][lg2[y-x+1]]]?f[x][lg2[y-x+1]]:f[y-(1<<lg2[y-x+1])+1][lg2[y-x+1]];
}
void solve(int l,int r)
{
	if (l>r) return;
	int mid=query(l,r);
	for (int i=max(mid-a[mid]+1,l);i<=min(mid,r-a[mid]+1);i++)
	if (nxt[i]>=i+a[mid]-1) ans++;
	solve(l,mid-1),solve(mid+1,r);
}
signed main()
{
	n=read();
	for (int i=1;i<=n;i++) a[i]=read();
	for (int i=1;i<=n;i++) f[i][0]=i;
	for (int j=1;j<20;j++)
		for (int i=1;i<=n;i++)
		if (a[f[i][j-1]]>a[f[min(i+(1<<j-1),n)][j-1]]) f[i][j]=f[i][j-1];
		else f[i][j]=f[min(i+(1<<j-1),n)][j-1];
	for (int i=2;i<=n;i++)
	{
		lg2[i]=lg2[i-1];
		if ((2<<lg2[i])<=i) lg2[i]++;
	}
	for (int i=1;i<=n;i++) p[i]=n+1;nxt[n+1]=n;
	for (int i=n;i>=1;i--)
	{
		nxt[i]=min(nxt[i+1],p[a[i]]-1);
		p[a[i]]=i;
	}
	solve(1,n);
	cout<<ans;
	return 0;
	//NOTICE LONG LONG!!!!!
}

  G:暴力O(n2k)dp顯然,即f[i][j]爲前i個數劃成j段時的最小值,則f[i][j]=min{f[k][j-1]+(i-k)*max{a[k+1..i]}}。考慮轉移時使用cdq分治。分最大值在右側仍是左側考慮。考慮最大值在左側時,右側從r向mid+1更新,過程當中能夠用來轉移的左側區間從l開始不斷擴大,即f[i][j]=min{f[k][j-1]+(i-k)*max{a[mid+1..i]}} (max{a[k+1..mid]}<=max{a[mid+1..i]}}。這個東西顯然能夠寫成a*i+b的形式,因而維護一個最小值構成的上凸殼在上面二分便可。最大值在右側同理,從mid+1向r更新,過程當中能夠用來轉移的左側區間從mid開始不斷擴大。具體實現時注意上面兩個過程若是直接作分別是按斜率從大到小加直線和從小到大加直線,要合併起來寫的話把後者的斜率取反再將查詢的x也取反便可。it

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1200000010
#define N 20010
#define M 110
#define double long double
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,m,a[N],f[N][M],suf[N],pre[N],tail;
struct line
{
	int k,b;
	int f(int x){return k*x+b;}
}q[N];
double cross(line x,line y)
{
	return (double)(y.b-x.b)/(x.k-y.k);
}
void ins(int k,int b)
{
	line t=(line){k,b};
	while (tail&&q[tail].k==k) t.b=min(t.b,q[tail--].b);
	while (tail>1&&cross(t,q[tail-1])<cross(q[tail],q[tail-1])) tail--;
	q[++tail]=t;
}
int query(int x)
{
	if (!tail) return inf;
	int l=1,r=tail-1,p=tail;
	while (l<=r)
	{
		int mid=l+r>>1;
		if (cross(q[mid],q[mid+1])>=x) p=mid,r=mid-1;
		else l=mid+1;
	}
	return q[p].f(x);
}
void solve(int l,int r)
{
	if (l==r) return;
	int mid=l+r>>1;
	solve(l,mid);
	for (int k=1;k<=m;k++)
	{
		
		suf[mid+1]=0;for (int i=mid;i>=l;i--) suf[i]=max(suf[i+1],a[i]);
		pre[mid]=0;for (int i=mid+1;i<=r;i++) pre[i]=max(pre[i-1],a[i]);
		int p=l;tail=0;
		for (int i=r;i>mid;i--)
		{
			while (suf[p+1]>=pre[i])
			{
				if (f[p][k-1]!=f[0][1]) ins(suf[p+1],f[p][k-1]-p*suf[p+1]);
				p++;
			}
			f[i][k]=min(f[i][k],query(i));
		}
		int mx=0;p=mid;tail=0;if (f[p][k-1]!=f[0][1]) ins(p,f[p][k-1]);
		for (int i=mid+1;i<=r;i++)
		{
			mx=max(mx,a[i]);
			while (mx>=a[p]&&p>l)
			{
				p--;
				if (f[p][k-1]!=f[0][1]) ins(p,f[p][k-1]);
			}
			f[i][k]=min(f[i][k],query(-mx)+i*mx);
		}
	}
	solve(mid+1,r);
}
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	n=read(),m=read();
	for (int i=1;i<=n;i++) a[i]=read();
	memset(f,42,sizeof(f));f[0][0]=0;
	solve(0,n);
	cout<<f[n][m];
	return 0;
	//NOTICE LONG LONG!!!!!
} 

  小小小小號。result:rank 13 rating +334class

相關文章
相關標籤/搜索