实力不济,用oeis也只有6题就滚粗了
A.夺宝奇兵
这个题只要想通了就特别简单,因为是往返的路,那么我就当成是两条线路同时走好了,假设每类宝藏的两个宝藏位置是a,b,那么我要从第 i 类宝藏走到第 i+1类宝藏,就有两种走法,(ai->ai+1,bi->bi+1)和(ai->bi+1,bi->ai+1),看哪一种短就走哪一种。
#include
#define ll long long
using namespace std;
const int maxn=1e5+10;
struct node
{
int x,y;
}a[maxn],b[maxn];
int ss(node t1,node t2)
{
return abs(t1.x-t2.x)+abs(t1.y-t2.y);
}
int main()
{
ll ans=0;
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&a[i].x,&a[i].y,&b[i].x,&b[i].y);
if(i==1)continue;
ans+=min(ss(a[i-1],a[i])+ss(b[i-1],b[i]),ss(a[i-1],b[i])+ss(b[i-1],a[i]));
}
ans+=ss(a[n],b[n]);
printf("%lld\n",ans);
}
C.最小边覆盖
先算好每个点的度数,如果有的点度数为0肯定No,然后枚举边,如果有一条边连接的两点度数同时>1,也是No,其他就Yes。
#include
#define ll long long
using namespace std;
const int maxn=2e5+10;
int d[maxn],u[maxn],v[maxn];
int main()
{
int n,m,flag=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u[i],&v[i]);
d[u[i]]++;
d[v[i]]++;
}
for(int i=1;i<=n;i++)
if(!d[i])flag=1;
for(int i=1;i<=m;i++)
{
if(d[u[i]]>1&&d[v[i]]>1)
flag=1;
}
if(flag)puts("No");
else puts("Yes");
}
F.小小马
如果从起点走不到终点,那肯定No,如果能的话,我们分析一下,假设当前的点是白点,由于马走日,那么下一个点肯定是黑点,因此如果终点和起点颜色相同,那肯定No,否则Yes
#include
#define ll long long
using namespace std;
int n,m,sx,sy,tx,ty,vis[25][25];
int ss()
{
if(n>=10&&m>=10)return 1;
if(n==2)
{
int k=abs(sy-ty);
if(sx==tx)
{
if(k%4==0)
return 1;
return 0;
}
if(k%2==0&&k%4)return 1;
return 0;
}
if(n==3)
{
if(m>3)return 1;
if(sx==2&&sy==2)return 0;
if(tx==2&&ty==2)return 0;
return 1;
}
return 1;
}
int main()
{
int t1,t2;
cin>>n>>m;
cin>>sx>>sy;
t1=((sx%2==sy%2)?0:1);
cin>>tx>>ty;
t2=((tx%2==ty%2)?0:1);
if(n>m)
{
swap(n,m);
swap(sx,sy);
swap(tx,ty);
}
if(!ss())
{
puts("No");
return 0;
}
if(t1==t2)puts("No");
else puts("Yes");
}
G.置置置换
oeis过的这题,dp解法待补....
#include
#define ll long long
using namespace std;
const int inf=1e9,mod=1e9+7;
int E[1005][1005];
ll d[1005];
void init()
{
for(int i=0;i<=1000;i++)
for(int j=0;j<=1000;j++)
E[i][j]=-inf;
}
int dfs(int n,int m)
{
if(E[n][m]!=-inf)return E[n][m];
if(m==0&&n==0)return E[n][m]=1;
if(m==0)return E[n][m]=0;
E[n][m]=(dfs(n,m-1)+dfs(n-1,n-m))%mod;
return E[n][m];
}
void sub(ll& x,ll y)
{
x=(x-y+mod)%mod;
}
void add(ll& x,ll y)
{
x=(x+y)%mod;
}
int main()
{
init();
for(int i=1;i<=1000;i++)
for(int j=1;j<=1000;j++)
dfs(i,j);
d[1]=1,d[2]=1,d[3]=2;
for(int i=4;i<=1000;i++)
{
d[i]=d[i-1]*(i-1)%mod;
ll res=0;
for(int j=2;j<=i-2;j++)
add(res,1ll*(j-1)*E[i-2][i-1-j]%mod);
sub(d[i],res);
}
int n;
while(~scanf("%d",&n))
printf("%lld\n",d[n]);
}
I.咆咆咆哮
update:被hack了,数据:3 100 70 1 2 3 4
设d[ i ]为召唤了 i 张a类卡片所能得到的最大值,那么可以看出来,d[ i+1 ]肯定是由d[ i ]的 i 张a类卡片+其他的一张a类卡片推出来,因此我枚举所有在d[ i ]中用的b类卡片 j,假设我要把第 j 张卡片换成a类,假设sum为在d[i]中用的所有bj的总和,那么,找到最优的 j,然后标记第 j 张卡片并且更新sum即可。
由于d[i+1]只和d[ i ]有关,因此我去掉了数组,用变量res代替。
#include
#define ll long long
using namespace std;
int a[1005],b[1005],vis[1005],n;
int main()
{
ll res=0,ans=0,sum=0;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i]>>b[i];
sum+=b[i];
}
int p;
for(int i=1;i<=n;i++)
{
p=0;
ll tmp2=0,tmp;
for(int j=1;j<=n;j++)
if(!vis[j])
{
tmp=res-1ll*b[j]*(i-1);
tmp+=a[j]+sum-b[j];
if(!p)
{
p=j;
tmp2=tmp;
continue;
}
if(tmp>tmp2)
{
tmp2=tmp;
p=j;
}
}
vis[p]=1;
sum-=b[p];
res=tmp2;
ans=max(ans,res);
}
printf("%lld\n",ans);
}
update:我这个思路是错的,d[ i+1 ]不一定只能由d[ i ]推出来,正解应该是枚举 i 个a类卡片,并且贪心取得最优值,假设每类卡片都是 b 类,如果我要把第 j 张卡片换成 a 类,那么总权值就会+a[ j ] - b[ j ]*i,把这个值记为s,我们分别记录这 n 张卡片的s值,按照从大到小排序,前 i 张卡片取a类,后面的卡片取b类求值就好了。
#include
#define ll long long
using namespace std;
struct node
{
ll a,b,s;
bool operator<(const node&t)const
{
return s>t.s;
}
}c[1005];
ll ans;
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>c[i].a>>c[i].b;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
c[j].s=c[j].a-c[j].b*i;
sort(c+1,c+1+n);
ll res=0;
for(int j=1;j<=n;j++)
if(j<=i)
res+=c[j].a;
else res+=c[j].b*i;
ans=max(ans,res);
}
cout<
K.两条路径
这个题其实巨水,两条路线交集只能是x,并且要并集总权值最大,我只要在以x为根节点的树找到四条权值最大的不一样的路线,把他们加起来就是答案。
#include
#define ll long long
using namespace std;
const int maxn=1e5+19;
vectorG[maxn];
int vis[maxn],a[maxn],f[maxn],p;
ll ans,mx;
void dfs(int u,int fa,ll res)
{
f[u]=fa;
if(res>mx)
{
mx=res;
p=u;
}
for(int i=0;is;
if(ans<0)printf("-"),ans=-ans;
while(ans!=0)
{
if(ans&1)s.push(1);
else s.push(0);
ans/=2;
}
while(!s.empty())
printf("%d",s.top()),s.pop();
puts("");
}
int main()
{
int n,u,v;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]==0)continue;
int tmp=1<<(abs(a[i])-1);
if(a[i]<0)a[i]=-tmp;
else a[i]=tmp;
}
for(int i=1;i