题目来源:https://ac.nowcoder.com/acm/contest/3007#question
这场又有好多AK的,我tcl… 可能会补2题左右,保证不咕~
先对两个序列从小到大排序,假如选第k大的,那我们肯定不能让第k大的这个碰到两个序列前1 - k 的元素,忽略他们,然后后面的头+尾 排个序取最小值
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,string> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-10;
const double pi=acos(-1);
int n,m;
int f[N],g[N];
int p[N];
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
r(n); r(m);
FOR(i,1,n) r(f[i]);
FOR(i,1,n) r(g[i]);
sort(f+1,f+n+1);
sort(g+1,g+n+1);
FOR(i,n-m+1,n){
p[i-n+m]=f[i]+g[n-i+n-m+1];
}
sort(p+1,p+m+1);
cout<<p[1]<<endl;
return 0;
}
这题应该就是类似于记忆化搜索,搜过的点标记上它的值,然后可以O(n)解决,难点就在于环的处理。但是这样想,从一个点开始搜,它最终的结局要么是撞到自己刚刚搜到的点成环,要么是碰到已经搜过的点把这个点的值+1即可。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,string> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-10;
const double pi=acos(-1);
int n,m;
int to[N];
bool vis[N];
int step[N];
int num[N];
int ans,loop;
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int dfs(int x,int stp)
{
//cout<
step[x]=stp;
int t=to[x];
if(vis[t]==0){
vis[t]=1;
int res=dfs(t,stp+1);
if(loop!=0){
if(loop==x){
loop=0;
}
return num[x]=res;
}
else{
return num[x]=res+1;
}
}
else{
if(num[t]>0) return num[x]=num[t]+1;
else if(num[t]==0){
loop=t;
if(t==x) loop=0;
return num[x]=step[x]-step[t]+1;
}
}
}
int main()
{
r(n);
FOR(i,1,n){
r(to[i]);
}
ans=0;
FOR(i,1,n){
if(!vis[i]){
vis[i]=1;
loop=0;
dfs(i,1);
}
}
FOR(i,1,n){
ans=max(num[i],ans);
// cout<
}
//cout<
cout<<ans<<endl;
return 0;
}
这题真的感觉我最近在哪里做过类似的题,应该是cf上!
首先对x从大到小排序,然后从左到右加入set,加之前先看他能不能在set中找到比他的y小的最大的点放在他上面
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-10;
const double pi=acos(-1);
int n,m;
struct node
{
int x,y,id;
bool operator< (node a){
return x<a.x;
}
}f[N];
int val[N];
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
r(n);
FOR(i,1,n){
r(f[i].x); r(f[i].y);
f[i].id=i;
}
sort(f+1,f+n+1);
set<pt> s;
int num=0;
FOR(i,1,n){
if(s.size()){
set<pt>::iterator it=s.lower_bound(mp(f[i].y,0));
if(it!=s.begin()){
it--;
if(val[it->second]==0){
val[it->second]=++num;
val[f[i].id]=num;
}
else{
val[f[i].id]=val[it->second];
}
s.erase(it);
}
}
s.insert(mp(f[i].y,f[i].id));
}
FOR(i,1,n){
if(val[i]==0) val[i]=++num;
}
cout<<num<<endl;
FOR(i,1,n) cout<<val[i]<<' ';
cout<<endl;
return 0;
}
反着思考,我们找不满足的 和总数相减即可
先对两个序列排序,这不会影响结果(可以理解的吧)
然后只要我们满足任意一个地方大于 他就是不满足的 没问题吧.
遍历一遍,对于当前的点i 我们找比这个点大的有多少个(二分搜索) 然后在这个点用比他大的点,那么后面任意怎么排都行ans=(ans+mult*cnt_h%mod*cc[n-i]%mod)%mod;
但是这个mult是干嘛的? 如果我们选不大于这个点的那就要看下一个点大不大嘛
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,char> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-10;
const double pi=acos(-1);
LL n,m;
int f[N];
int g[N];
LL cc[N];
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
r(n);
cc[0]=1;
FOR(i,1,n){
cc[i]=cc[i-1]*i%mod;
}
FOR(i,1,n){
r(f[i]);
}
FOR(i,1,n) r(g[i]);
sort(g+1,g+n+1);
sort(f+1,f+n+1);
LL ans=0,mult=1;
FOR(i,1,n){
LL cnt_l=upper_bound(f+i,f+n+1,g[i])-f-i;
LL cnt_h=(n-i+1)-cnt_l;
ans=(ans+mult*cnt_h%mod*cc[n-i]%mod)%mod;
//cout<
if(cnt_h==n-i+1||cnt_h==0){
break;
}
else{
mult=mult*cnt_l%mod;
}
}
LL res=(cc[n]-ans+mod)%mod;
cout<<res<<endl;
return 0;
}
这题还是没想到那么深…
对于1e4组数据,我们的复杂度基本不能超过1e4 我的复杂度是带了个常数的1e4:首先素数筛,这里的 素数筛不是筛1018 以内的,筛出N1/4 以内的就够用了 具体原因请听我细细道来: A 3 B = N A^3B=N A3B=N 我们只需要对N进行素数分解 然后取其素数的幂/3的结果 即是A 但是不经处理的话 复杂度是1e6 , 我们再仔细想 假如我们取N1/4以内的素数去分解 之后会剩下一个M,这个M里面包含的是N中大于N1/4的素数 (假如有素数的幂超过3 另外还包含其他没超过3的,那这个M=(N1/4+x)3*(N1/4+y)>N 所以是必不可能的 所以如果M对答案有贡献,它必然是完全立方数!
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const int bb=18;
const double eps=1e-10;
const double pi=acos(-1);
LL n,m;
bool isprime[N];
int prime[N];
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
FOR(i,2,1e5){
if(isprime[i]==0){
prime[++m]=i;
for(int j=2;1ll*i*j<=1e5;j++){
isprime[i*j]=1;
}
}
}
int t; r(t);
while(t--){
r(n);
LL l=1,r=4e4,nn;
LL ans=1;
while(l<=r){
LL mid=(l+r)>>1;
if(mid*mid*mid*mid>n){
nn=mid;
r=mid-1;
}
else l=mid+1;
}
FOR(i,1,m){
int t=prime[i];
if(t>nn||t>n) break;
int cnt=0;
while(n%t==0){
cnt++;
n/=t;
if(cnt==3){
cnt=0;
ans*=t;
}
}
}
//cout<
l=1,r=1e6+2;
LL res=0;
while(l<=r){
LL mid=(l+r)>>1;
if(mid*mid*mid<=n){
res=mid;
l=mid+1;
}
else r=mid-1;
}
//cout<
if(res*res*res==n){
ans*=res;
}
cout<<ans<<endl;
}
return 0;
}
计算每次操作的贡献即可,因为每次操作的每个格子的i+j是很容易算出来的(m*x+n*y-x-y)+(n+1)*n/2+(m+1)*m/2;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,string> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-10;
const double pi=acos(-1);
int n,m;
int f[N],g[N];
int p[N];
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
int k;
r(n); r(m); r(k);
LL ans=0;
FOR(i,1,k){
int x,y,z;
rrr(x,y,z);
LL dmg=(m*x+n*y-x-y)+(n+1)*n/2+(m+1)*m/2;
ans=(ans+dmg*z%mod)%mod;
//cout<
}
cout<<ans<<endl;
return 0;
}
就是括号匹配…
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,string> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-10;
const double pi=acos(-1);
int n,m;
char str[N];
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
int t;
r(t);
while(t--){
r(n);
scanf("%s",str+1);
stack<char> s;
FOR(i,1,n){
if(s.size()){
if(str[i]==')'&&s.top()=='('){
s.pop();
}
else{
s.push(str[i]);
}
}
else{
s.push(str[i]);
}
}
cout<<s.size()<<endl;
}
return 0;
}
这题如果考虑两边云的运动,处理会比较复杂,我们考虑他们的相对运动。以第一象限的云为参考系,那么第三象限的云一步往右和上各走一步
黑色为坐标轴 蓝色为矩形 红色为y=-x 绿线为垂直于y=-x的直线 紫色为坐下矩形投影平移出来的线段 深蓝色为右上矩形投影平移出来的线段
不难发现,只要矩形关于y=-x的投影相交即 他们平移会相交
现在矩形左上顶点为C 那么 O B = x , B C = y OB=x,BC=y OB=x,BC=y,我们要求的是他投影之后的坐标 t t t ,因为 A B = B C AB=BC AB=BC 故 O A = x − y OA=x-y OA=x−y 那么 2 t = O A \sqrt{2}t=OA 2t=OA 但是这个根号完全不需要,因为所有的坐标都带根号 和都不带最终并不影响结果啊,我们去掉无妨
后面的统计排个序就好找了~
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const int bb=18;
const double eps=1e-10;
const double pi=acos(-1);
LL n,m;
struct node
{
int x,type,lr;
node(){};
node(int xx,int tt,int ll){
x=xx; type=tt; lr=ll;
}
bool operator< (node b)
{
if(x==b.x) return lr>b.lr;
return x<b.x;
}
}f[N];
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
r(n); r(m);
int cnt=0;
FOR(i,1,n){
int a,b,c,d;
rrr(a,b,c); r(d);
f[++cnt]=node(a-b,1,1);
f[++cnt]=node(c-d,1,-1);
}
FOR(i,1,m){
int a,b,c,d;
rrr(a,b,c); r(d);
f[++cnt]=node(a-b,0,1);
f[++cnt]=node(c-d,0,-1);
}
sort(f+1,f+cnt+1);
int c1=0,c2=0;
LL ans=0;
FOR(i,1,cnt){
if(f[i].type) c1+=f[i].lr;
else c2+=f[i].lr;
if(f[i].lr==1){
if(f[i].type) ans+=c2;
else ans+=c1;
}
}
cout<<ans<<endl;
return 0;
}
这题考察的应该是 最小生成树+最短路+并查集 出题人用心啦~
很容易知道的是在一个树上最短的莫过于两点之间的边,其他任意的边都是这些小边的和,所以我们构造最小生成树,跑一遍最短路得到各点之间的距离,再看大边之间是否符合即可(其中最小生成树用到了并查集)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const int bb=18;
const double eps=1e-10;
const double pi=acos(-1);
LL n,m;
int dad[M];
LL dis[M][M];
int in[M][M];
int rt[M][M];
struct node
{
int x,y,v;
node(){};
node(int xx,int yy,int vv)
{
x=xx; y=yy; v=vv;
}
friend bool operator< (node a,node b)
{
return a.v>b.v;
}
};
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int seek(int k)
{
return k==dad[k]?k:dad[k]=seek(dad[k]);
}
int main()
{
r(n);
priority_queue<node> q;
priority_queue<int,vector<int> ,greater<> > ans;
FOR(i,1,n){
FOR(j,1,n){
r(in[i][j]);
if(i!=j){
rt[i][j]=1e9+7;
q.push(node(i,j,in[i][j]));
}
}
dad[i]=i;
}
int cnt=0;
while(q.size()&&cnt<n-1){
node now=q.top();
q.pop();
//cout<
int x=seek(now.x);
int y=seek(now.y);
if(x!=y){
cnt++;
dad[x]=y;
rt[now.x][now.y]=now.v;
rt[now.y][now.x]=now.v;
ans.push(now.v);
}
}
FOR(k,1,n){
FOR(i,1,n){
FOR(j,1,n){
if(i!=j&&j!=k&&i!=k) rt[i][j]=min(rt[i][k]+rt[k][j],rt[i][j]);
}
}
}
bool flag=1;
FOR(i,1,n){
FOR(j,1,n){
if(rt[i][j]!=in[i][j]){
flag=0;
break;
}
}
}
if(flag){
cout<<"Yes\n";
while(ans.size()){
cout<<ans.top()<<endl;
ans.pop();
}
}
else cout<<"No\n";
return 0;
}
设三个圆的半径分别为a b c,那三个边长即为a+b,b+c,a+c
a + b + c = ( x + y + z ) / 2 a+b+c=(x+y+z)/2 a+b+c=(x+y+z)/2(x,y,z为输入的边长)如果能构成三角形,那么很容易知道一边小于两边之和,设 x = a + b , y = a + c , z = b + c 易 得 c = ( x + y + z ) / 2 − x , b = ( x + y + z ) / 2 − z , a = ( x + y + z ) / 2 − y x=a+b,y=a+c,z=b+c 易得c=(x+y+z)/2-x,b=(x+y+z)/2-z,a=(x+y+z)/2-y x=a+b,y=a+c,z=b+c易得c=(x+y+z)/2−x,b=(x+y+z)/2−z,a=(x+y+z)/2−y ,其中a b c一定都大于0 故一定存在!
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rrr(x,y,z) read(x);read(y);read(z)
#define FOR(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef long long LL;
typedef pair<int,string> pt;
const int N=1e6+5;
const int M=2e3+5;
const int INF=0x7fffffff;
const int mod=1e9+7;
const double eps=1e-10;
const double pi=acos(-1);
int n,m;
template<class T>
inline void read(T &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
int a,b,c;
rrr(a,b,c);
double tot=(a+b+c)*1.0/2;
if(a+b>c&&a+c>b&&b+c>a){
if(tot>a&&tot>b&&tot>c){
cout<<"Yes\n";
double f[4];
f[1]=tot-a;
f[2]=tot-b;
f[3]=tot-c;
sort(f+1,f+4);
printf("%.2f %.2f %.2f\n",f[1],f[2],f[3]);
}
else{
cout<<"No\n";
}
}
else{
cout<<"wtnl\n";
}
return 0;
}