#16简单题
[AGC004C] AND Grid
题目中有个重要条件:第一行,第一列,最后一行,最后一列都没有涂色点。可以很快得到一种构造方法,在第一张图中将第一列和奇数行涂色,在第二张图中将最后一列和偶数行涂色。此时两张图染色的格子没有交。再将所有在原图中染色的点在两张图中都染色即可。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=510;
int n,m;
char s[N][N];
void solve(){
read(n),read(m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
s[i][j]=getchar();
while(s[i][j]!='.'&&s[i][j]!='#'){
s[i][j]=getchar();
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(j==m){
putchar('.');
continue;
}
if(j==1||i%2||s[i][j]=='#'){
putchar('#');
}
else{
putchar('.');
}
}
putchar('\n');
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(j==1){
putchar('.');
continue;
}
if(j==m||i%2==0||s[i][j]=='#'){
putchar('#');
}
else{
putchar('.');
}
}
putchar('\n');
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
Returning Home
容易想到在传送点间建图,再求最短路。但是边数太大,考虑优化建图。
注意到一件事,若 \(i,j\) 间存在一个中间点 \(k\),\(i\rightarrow k\rightarrow j\) 和 \(i\rightarrow j\) 是本质相同的。所以可以按两维分别将点排序,从排序后的第 \(i\) 个点连边向 第 \(i+1\) 个点。这是边数优化到了 \(O(m)\) 级别,复杂度为 \(O(m\log m)\)。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=1e5+10;
int n,m,x[N],y[N],id[N],head[N],tot=1,dis[N],vis[N];
bool cmp1(int a,int b){
return x[a]==x[b]?y[a]<y[b]:x[a]<x[b];
}
bool cmp2(int a,int b){
return y[a]==y[b]?x[a]<x[b]:y[a]<y[b];
}
struct edge{
int v,w,nxt;
}e[N<<2];
void add(int u,int v,int w){
e[++tot].v=v;
e[tot].w=w;
e[tot].nxt=head[u];
head[u]=tot;
}
void add_e(int u,int v,int w){
add(u,v,w);
add(v,u,w);
}
void solve(){
read(n),read(m);
int stx,sty,edx,edy;
read(stx),read(sty),read(edx),read(edy);
for(int i=1;i<=m;i++){
read(x[i]),read(y[i]);
id[i]=i;
}
sort(id+1,id+m+1,cmp1);
for(int i=1;i<m;i++){
add_e(id[i],id[i+1],min(abs(x[id[i]]-x[id[i+1]]),abs(y[id[i]]-y[id[i+1]])));
}
sort(id+1,id+m+1,cmp2);
for(int i=1;i<m;i++){
add_e(id[i],id[i+1],min(abs(x[id[i]]-x[id[i+1]]),abs(y[id[i]]-y[id[i+1]])));
}
priority_queue<pii>q;
for(int i=1;i<=m;i++){
dis[i]=min(abs(x[i]-stx),abs(y[i]-sty));
q.push(mp(-dis[i],i));
}
while(q.size()){
int u=q.top().second;
q.pop();
if(vis[u]){
continue;
}
vis[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].v,w=e[i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
q.push(mp(-dis[v],v));
}
}
}
int ans=abs(stx-edx)+abs(sty-edy);
for(int i=1;i<=m;i++){
ans=min(ans,dis[i]+abs(edx-x[i])+abs(edy-y[i]));
}
write_endl(ans);
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
[AGC037C] Numbers on a Circle
将操作改为 \(b_i\rightarrow b_i-b_{i-1}-b_{i+1}\),若一个操作合法,则 \(b_i>b_{i-1}+b_{i+1}\)。当存在 \(b_i>a_i\) 且无法进行操作时,无解。最大的没有满足 \(b_i=a_i\) 的树肯定是可选的,使用优先队列维护选取过程。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define int long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=2e5+10;
int n,a[N],b[N];
void solve(){
read(n);
for(int i=1;i<=n;i++){
read(a[i%n]);
}
for(int i=1;i<=n;i++){
read(b[i%n]);
}
priority_queue<pii>q;
for(int i=0;i<n;i++){
if(b[i]<a[i]){
puts("-1");
return;
}
if(b[i]>a[i]){
q.push(mp(b[i],i));
}
}
int ans=0;
while(q.size()){
int i=q.top().second;
q.pop();
int del=b[i]-a[i],delta=b[(i-1+n)%n]+b[(i+1)%n];
if(del/delta==0){
write_endl(-1);
return;
}
ans+=del/delta;
b[i]-=del/delta*delta;
if(b[i]>a[i]){
q.push(mp(b[i],i));
}
}
write_endl(ans);
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
[COCI2020-2021#2] Sjekira
贪心考虑,一个点如果权值小则让它多产生贡献,反之少产生贡献。
将删边转加边,将点按照点权排序。对于一个点,每次只和比它点权小的点合并。正确性显然,因为这样不会使得一条边两端的点权更大。可以用并查集维护连通块。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pdi pair<double,int>
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define eps 1e-9
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=1e5+10;
int n,a[N],id[N],fa[N],vis[N];
ll ans=0;
vector<int>e[N];
int getfa(int u){
if(fa[u]!=u){
fa[u]=getfa(fa[u]);
}
return fa[u];
}
bool cmp(int x,int y){
return a[x]<a[y];
}
signed main(){
read(n);
for(int i=1;i<=n;i++){
read(a[i]);
id[i]=fa[i]=i;
}
sort(id+1,id+n+1,cmp);
for(int i=1,u,v;i<n;i++){
read(u),read(v);
e[u].pb(v);
e[v].pb(u);
}
for(int i=1;i<=n;i++){
int u=id[i];
vis[u]=1;
for(auto v:e[u]){
if(!vis[v]){
continue;
}
u=getfa(u),v=getfa(v);
if(u!=v){
ans+=a[u]+a[v];
fa[v]=u;
a[u]=max(a[u],a[v]);
}
}
}
write_endl(ans);
return 0;
}
Kate and imperfection
按照贪心的方法,我们先将所有的质数加入到集合中,接下来加入最小的未被加入过的数 \(4\),此时答案为 \(2\),加入 \(6\) 后,答案为 \(3\),但是我们不能加入 \(8\),这样答案会增大,但是加入 \(9\) 则不会。可以发现规律,\(i\) 在答案为 \(\frac{i}{mn}\) 时加入集合最大,其中 \(mn\) 表示 \(i\) 的最小质因子。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=5e5+10;
int n,prime[N],min_ins[N],cnt,ans[N];
void solve(){
read(n);
min_ins[1]=1;
for(int i=2;i<=n;i++){
if(!min_ins[i]){
min_ins[i]=1;
prime[++cnt]=i;
}
for(int j=1;j<=cnt&&prime[j]*i<=n;j++){
min_ins[prime[j]*i]=i;
if(i%prime[j]==0){
break;
}
}
ans[min_ins[i]]++;
}
for(int cnt=1;cnt<=n;cnt++){
for(int i=1;i<=ans[cnt];i++){
write_space(cnt);
}
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
Little Elephant and Broken Sorting
已知期望是独立的,所以可以将期望逆序对数拆为每对数为逆序对的期望和。令 \(f_{i,j}\) 表示 \(p_i>p_j\) 的期望。初始若 \(p_i>p_j\),则 \(f_{i,j}=1\)。对于一次交换 \((x,y)\),\(\forall x\not=y\),则 \(f_{i,x}=f_{i,y}=0.5(f_{i,x}+f_{i,y}),f_{y,i}=f_{x,i}=0.5(f_{x,i}+f_{y,i})\),\(f_{x,y}=f_{y,x}=0.5\)。
最后求所有的 \(i<j\) 的 \(f_{i,j}\) 的和。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=1010;
int a[N],n,m;
double f[N][N];
void solve(){
read(n),read(m);
for(int i=1;i<=n;i++){
read(a[i]);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[i][j]=(a[i]>a[j]);
}
}
for(int i=1;i<=m;i++){
int x,y;
read(x),read(y);
for(int j=1;j<=n;j++){
f[j][x]=f[j][y]=(f[j][x]+f[j][y])/2;
f[x][j]=f[y][j]=(f[x][j]+f[y][j])/2;
}
f[x][y]=f[y][x]=0.5;
}
double ans=0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
ans+=f[i][j];
}
}
cout<<fixed<<setprecision(10)<<ans<<'\n';
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
Moderate Modular Mode
分类讨论。
若 \(x>y\),当 \(n>x\) 时,\(y<n\),即 \(n\bmod x\equiv y\),则 \(n=y+kx,k\in \mathbb{Z}\) 是一个合法的解。
若 \(x=y\),\(n=x\) 是一个合法的解。
若 \(x<y\),注意到 \(y<2x\) 时,\(n=\frac{y+x}{2}\) 是一个合法的解。所以我们找到 \(d\),满足 \(d=kx,k\in \mathbb{Z},d<y\),令 \(n=d+\farc{y-d}{2}\) 即可。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
int x,y;
void solve(){
read(x),read(y);
if(y<x){
write_endl(x+y);
}
else if(y==x){
write_endl(x);
}
else{
int mul=y/x;
int d=mul*x;
write_endl(d+(y-d)/2);
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t;
read(t);
while(t--){
solve();
}
return 0;
}