题意:给你两个点坐标,你可以任意选取两个点(坐标均为整数),看能否构造一个正方形。水题
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int tmp;
void print(int x1,int y1,int x2,int y2)
{
printf("%d %d %d %d\n",x1,y1,x2,y2);
}
int main()
{
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
if(x1==x2)
print(x1+abs(y1-y2),y1,x2+abs(y1-y2),y2);
else if(y1==y2)
print(x1,y1+abs(x1-x2),x2,y2+abs(x1-x2));
else if(abs(x1-x2)==abs(y1-y2))
print(x1,y2,x2,y1);
else
puts("-1");
}
题意:让你选择两个数ai aj,使得他们的差最大,问有多少种选法。
水题,不过要注意一下整个序列的值都相同的情况
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
int n,x,mn=1e9+1,mx=0,t1=1,t2=1;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
if(x<mn)mn=x,t1=1;
else if(x==mn)t1++;
if(x>mx)mx=x,t2=1;
else if(x==mx)t2++;
}
ll ans=1ll*t1*t2;
if(mx==mn)
ans=1ll*n*(n-1)/2;
printf("%d %lld\n",mx-mn,ans);
}
题意:有k辆车,每天都要送n位学生,要求不能两位学生每天都坐同一辆车。
思路:dfs一下即可,但是细节要注意,如果k太大,dfs会超时,所以如果k太大把k缩小的合理的范围就行(k=min(k,n))。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int gao(int n,int k)
{
int res=0;
while(n)
{
if(n<=1)return res;
res++;
n/=k;
}
return res;
}
int a[1005][1005],b[1005],cur,n,k,d;
void dfs(int x)
{
if(cur>=n)return;
if(x==d+1)
{
cur++;
for(int i=1;i<=d;i++)
a[i][cur]=b[i];
return;
}
for(int i=1;i<=k;i++)
{
b[x]=i;
dfs(x+1);
}
}
int main()
{
scanf("%d%d%d",&n,&k,&d);
if(k==1)
{
if(n!=1)
printf("-1"),exit(0);
for(int i=1;i<=d;i++)
printf("%d\n",1);
return 0;
}
int t=gao(n,k);
int tmp=pow(k,t);
if(tmp<n)t++;
if(d<t)
printf("-1"),exit(0);
k=min(k,n);
dfs(1);
for(int i=1;i<=d;i++)
{
for(int j=1;j<n;j++)
printf("%d ",a[i][j]);
printf("%d\n",a[i][n]);
}
}
D. Pashmak and Parmida's problem
题意:定义 f(l ,r ,x)表示区间 [ l r ]有多少个数等于x,求所有的 i<j 使得 f( 1, i ,a[i])>f( j, n, a[j])。
思路:先倒序求出 [ i n] 有多少个数等于ai并记录在树状数组,然后正序遍历 [1 , i ] ,求出有当前等于ai 的个数x ,从树状数组求[1 ,x -1]区间和即可,记得要从树状数组减去 f( i , n, a[i])哦。
#include<bits/stdc++.h>
#define ll long long
#define low(x) x&-x
using namespace std;
const int maxn=1e6+10;
map<int,int>mp,mp2;
int a[maxn],c[maxn],n;
void up(int x,int v)
{
for(;x<=n;x+=low(x))
c[x]+=v;
}
int qu(int x)
{
int res=0;
for(;x;x-=low(x))
res+=c[x];
return res;
}
int main()
{
ll ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=n;i;i--)
mp[a[i]]++,up(mp[a[i]],1);
for(int i=1;i<=n;i++)
{
mp2[a[i]]++;
up(mp[a[i]],-1);
mp[a[i]]--;
ans+=qu(mp2[a[i]]-1);
}
printf("%lld\n",ans);
}
题意:求一条最长的路径,路径上的边权递增。
思路:刚开始把边看成点进行dp,然后成功超时,看了题解后觉得这题有点巧妙....
对边权排序,然后枚举边,很容易想到当前的边 u v,d[v]=d[u]+1,但是这题有坑,万一这条边和前面一条边相等可能会错误更新了d[u]从而d[v]求大了,因此需要把所有权值相同的边统一处理,设f[u]为走到点u的最长路,设d[i]为一个临时数组,表示由前面与wi不同的边更新到第 i 条边的长度,然后统一更新 f[v] 就行
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
struct node
{
int u,v,w;
bool operator<(const node&t)const
{
return w<t.w;
}
};
node e[maxn];
int d[maxn],f[maxn];
int main()
{
int n,m,ans=0,t=1;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
sort(e+1,e+1+m);
for(int i=1;i<=m;i++)
{
int u=e[i].u,v=e[i].v;
d[i]=f[u]+1;
if(e[i].w!=e[i+1].w)
{
for(t;t<=i;t++)
f[e[t].v]=max(f[e[t].v],d[t]);
}
ans=max(ans,d[i]);
}
printf("%d\n",ans);
}