双11%你题

写在前面的话:
由于博主太菜了所以T3的代码咕咕咕了

T1

先来看看正解

我们从样例入手
23996
答案是23899
发现如果原数不满足条件,那么要使答案最大,就一定是从某一位开始填9。
从哪一位开始填9呢?
看样例,发现最后一位6不满足单调不减的条件,所以把6换成了9。又因为要满足答案≤原数,所以倒数第二位-1,变成8。发现倒数第三位是9,也要-1。再往前看,是3,满足条件,不再-1,输出。

一些坑点

1.要注意判前导零
2.注意答案如果是0,那么不要在前导零的地方判没了

蒟蒻的另类AC思路

AC前提:评测姬开栈
看到这个题,可以联想到数位dp有木有。
由于是求最大的满足条件的数,所以我们不从0开始填,而是从up开始填,一旦找到了第一个符合条件的数就一路return回去。如果评测姬不给开栈,那么1e5的点会RE,开了栈就可以AC了。
code:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#define pa pair<int,int>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int x[100009],ans[100009],cnt,fd;
void dfs(int now,int lst,bool lim)
{
	if(now==0) 
	  {fd=1;return ;}
	int up=(lim)?x[cnt-now+1]:9;
	for(int i=up;i>=lst;i--)
	{
		ans[now]=i;
		dfs(now-1,i,lim&&(i==up));
		if(fd) return ;
	}
}
int main()
{
	freopen("increase.in","r",stdin);
	freopen("increase.out","w",stdout);
	char ch=getchar();
	while(ch<'0'||ch>'9')
    {
    	if(ch=='-')x[0]=1;
    	ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x[++cnt]=ch^48;
		ch=getchar();
	}
	dfs(cnt,0,1);
	int st=cnt;
	while(ans[st]==0&&st>1) st--;
	for(int i=st;i>=1;i--)
	 printf("%d",ans[i]);
}

T2



60pts
把式子打上即可
80pts
需要(O(n^2))的做法
感觉在暴力(O(n^4))里面有好多量被重复计算了,那我们是否可以先处理出来这些重复的量来进行优化呢?
当然可以辣。通过一系列打表找规律可以得到每个逆序对对答案的贡献是(i*(n-j+1)*a_i*a_j),那么可以(O(n^2))找逆序对然后统计答案(蒟蒻的80pts的思路太绕所以就不放代码了)
100pts
此题中显然是要找逆序对,所以我们容易想到归并排序/树状数组求逆序对等操作。在此题中不仅要找到逆序对,而且要统计对答案的贡献。对归并排序来说,可以记录每个元素原本的编号然后统计答案。对于树状数组来说,可以在树状数组里维护(a_i*i)。若此时查询(a_j)对答案的贡献,查询前缀和后再乘(a_j imes (n-j+1))即可。

一些坑点

由于取模数巨大,可能会出现两个数乘起来爆掉(unsigned long long)的情况,所以我们需要龟速乘来解决这个问题。
龟速乘:用加法模拟乘法,同时为了复杂度不过高,使用快速幂的思想,可以在取模数巨大的时候答案正确
龟速乘代码:

ll mul(ll x,ll y)
{
	long long rtn=0;
	while(y!=0){
		if(y&1==1)rtn+=x,rtn%=mod;
		x=x+x,x%=mod;
		y>>=1; 
	}
	return rtn;
}

ACcode:(只有树状数组版的)(归并我不会)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#define pa pair<int,int>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
inline ull read()
{
	char ch=getchar();
	ull x=0; 
	bool f=0;
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return f?-x:x;
}
const ll mod=1000000000007;
ull n,b[400009],c[400009],wa[400009],sum[4000009],ans;
struct lsh{
	ull zhi;
	int id;
}a[400009];
bool cmp(lsh a,lsh b)
{
	if(a.zhi!=b.zhi) return a.zhi<b.zhi;
	return a.id<b.id;
}
ll mul(ll x,ll y)
{
	long long rtn=0;
	while(y!=0){
		if(y&1==1)rtn+=x,rtn%=mod;
		x=x+x,x%=mod;
		y>>=1; 
	}
	return rtn;
}
ll lowbit(ll x)
{
	return x&(-x);
}
void update(ull x,ull up)
{
	for(;x<=n;x+=lowbit(x))
	{
	   sum[x]+=up;
	   sum[x]=(sum[x]+mod)%mod;
	}
}
ll qry(ll x)
{
	ll rtn=0;
	for(;x;x-=lowbit(x))
	{
	  rtn+=sum[x];
	  rtn=(rtn+mod)%mod;
	}
	return rtn;
}
int main()
{
 // freopen("multiplication.in","r",stdin);
 // freopen("multiplication.out","w",stdout);
  n=read();
  for(int i=1;i<=n;i++)
   a[i].zhi=read(),a[i].id=i;
   sort(a+1,a+1+n,cmp);
  for(int i=1;i<=n;i++)
   b[a[i].id]=i,wa[a[i].id]=a[i].zhi;
  for(int i=1;i<=n;i++)
  {
  	ull x=qry(n-b[i]+1);
  	ans=(ull)(ans+(ull)(mul(mul(x,(n-i+1)),wa[i]))+mod)%mod;
    ans=(ans+mod)%mod;
  	ull ud=(ull)(mul(i,wa[i])+mod)%mod;
  	update(n-b[i]+1,ud);
  } 
  cout<<ans<<endl;
}

T3




30pts
暴力枚举每两个矩形是否有交集,计算面积是否等于一个完整的矩形
正解
扫描线
然鹅我不会
我们考虑(perfect)的数据有什么优美的性质。
发现最终组成的大矩形的角上的点一定是某个矩形的角而且只会出现一次,边上的点一定是某个矩形的边或者是两个矩形分界处的角上的点。
那么我们以大矩形内的每一个点(是矩形分界处的点)画坐标轴,每个象限只有一个矩形(边界之外的手动补齐)。当然会有一个矩形占据两个象限的情况,要特判一下。
如果一个点是一个矩形的一个角的话,那么就把那个所在矩形的象限标记为true,最后看每个点的每个象限是否都恰好标记了一次。
由于我太弱了,不会写正解,所以让我们康康神仙std

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

using namespace std;

#define INF 2147483647
#define maxn 100010

int n,rectangles[maxn][4];

struct point
{
	int x,y,d;
	point(){}
	point(int a,int b,int c)
	{
		x=a;y=b;d=c;
	}
}p[maxn<<2],q[maxn<<2];

bool operator<(const point &a,const point &b)
{
	if (a.x!=b.x) return a.x<b.x;
	return a.y<b.y;
}

bool cmp(const point &a,const point &b)
{
	if (a.y!=b.y) return a.y<b.y;
	return a.x<b.x;
}

struct line
{
	int x,y,l,r,d;
	line(){}
	line(int a,int b,int c,int e)
	{
		x=a;y=a;l=b;r=c;d=e;
	}
}vert[maxn<<2],hori[maxn<<2];

bool operator<(const line &a,const line &b)
{
	if (a.x!=b.x) return a.x<b.x;
	if (a.l!=b.l) return a.l<b.l;
	return a.r<b.r;
}

bool isRectangleCover() {
	int minx=INF,maxx=-INF,miny=INF,maxy=-INF;
	for (int a=0;a<n;a++)
	{
		minx = min(minx,rectangles[a][0]);
		maxx = max(maxx,rectangles[a][2]);
		miny = min(miny,rectangles[a][1]);
		maxy = max(maxy,rectangles[a][3]);
	}
	long long s=(0ll+maxx-minx)*(0ll+maxy-miny);
	for (int a=0;a<n;a++)
		s -= (0ll+rectangles[a][2]-rectangles[a][0])*(0ll+rectangles[a][3]-rectangles[a][1]);
	if (s) return false;
	int m=0,n1=0,n2=0;
	for (int a=0;a<n;a++)
	{
		p[++m]=point(rectangles[a][0],rectangles[a][1],1);
		p[++m]=point(rectangles[a][2],rectangles[a][1],2);
		p[++m]=point(rectangles[a][2],rectangles[a][3],4);
		p[++m]=point(rectangles[a][0],rectangles[a][3],8);
		vert[++n1]=line(rectangles[a][1],rectangles[a][0],rectangles[a][2],3);
		vert[++n1]=line(rectangles[a][3],rectangles[a][0],rectangles[a][2],12);
		hori[++n2]=line(rectangles[a][0],rectangles[a][1],rectangles[a][3],9);
		hori[++n2]=line(rectangles[a][2],rectangles[a][1],rectangles[a][3],6);
	}
	sort(p+1,p+m+1);
	sort(vert+1,vert+n1+1);
	sort(hori+1,hori+n2+1);
	int k=0;
	for (int a=1;a<=m;)
	{
		int b=a+1,s=p[a].d,x=p[a].x,y=p[a].y;
		while (b<=m && p[b].x==x && p[b].y==y)
		{
			if (s&p[b].d) return false;
			s|=p[b].d;
			b++;
		}

		int news=0;
		if (x==minx) news|=6;
		if (x==maxx) news|=9;
		if (y==miny) news|=12;
		if (y==maxy) news|=3;
		if (news&s) return false;
		s|=news;
		q[++k] = point(x,y,s);

		a=b;
	}
	sort(q+1,q+k+1);
	for (int a=1;a<=n2;a++)
	{
		int x=hori[a].x,y1=hori[a].l,y2=hori[a].r,s=hori[a].d;
		int l=0,r=k;
		while (l+1!=r)
		{
			int m=(l+r)>>1;
			if (q[m].x>x || (q[m].x==x && q[m].y>y1)) r=m;
			else l=m;
		}
		while (r<=k && q[r].x==x && q[r].y<y2)
		{
			if (q[r].d&s) return false;
			q[r].d|=s;
			r++;
		}
	}

	sort(q+1,q+k+1,cmp);
	for (int a=1;a<=n1;a++)
	{
		int y=vert[a].y,x1=vert[a].l,x2=vert[a].r,s=vert[a].d;
		int l=0,r=k;
		while (l+1!=r)
		{
			int m=(l+r)>>1;
			if (q[m].y>y || (q[m].y==y && q[m].x>x1)) r=m;
			else l=m;
		}
		while (r<=k && q[r].y==y && q[r].x<x2)
		{
			if (q[r].d&s) return false;
			q[r].d|=s;
			r++;
		}
	}
	return true;
	return true;
}

int main()
{
	freopen("matrix.in","r",stdin);
	freopen("matrix.out","w",stdout);
	int t;
	scanf("%d",&t);
	for (;t--;)
	{
		scanf("%d",&n);
		for (int a=0;a<n;a++)
			for (int b=0;b<4;b++)
				scanf("%d",&rectangles[a][b]);
		if (isRectangleCover()) printf("Perfect
");
		else printf("Guguwansui
");
	}

	return 0;
}
原文地址:https://www.cnblogs.com/lcez56jsy/p/11840720.html