传送门
A Zoning Restrictions Again
题解:有限制的点跟题中统一要求的取min,没有限制的点直接按照统一限制;
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000010;
int a[N];
void Test(){
int n,h,m;
cin>>n>>h>>m;
for(int i=1;i<=n;i++) a[i]=h;
while(m--){
int l,r,x;
cin>>l>>r>>x;
for(int i=l;i<=r;i++) a[i]=min(a[i],x);
}
int res=0;
for(int i=1;i<=n;i++) res+=a[i]*a[i];
cout<<res<<"\n";
}
int main() {
ios::sync_with_stdio(false);
// cin.tie(0);
int t=1;
// cin>>t;
// int ncase=1;
while(t--)
Test();
}
/*
1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End
*/
B - Double Matrix
题解:可以有贪心得出,让一个矩阵取到两个矩阵同一位置的min,另一个取max,然后判断是否满足题意;
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1010;
int a[N][N];
int b[N][N];
void Test(){
int n,m;
cin>>n>>m;
int flag=0;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>a[i][j];
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>b[i][j];
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(a[i][j]<b[i][j]) swap(a[i][j],b[i][j]);
for(int i=1;i<=n;i++) for(int j=1;j<m;j++) if(a[i][j]>=a[i][j+1]) flag=1;
for(int i=1;i<=m;i++) for(int j=1;j<n;j++) if(a[j][i]>=a[j+1][i]) flag=1;
for(int i=1;i<=n;i++) for(int j=1;j<m;j++) if(b[i][j]>=b[i][j+1]) flag=1;
for(int i=1;i<=m;i++) for(int j=1;j<n;j++) if(b[j][i]>=b[j+1][i]) flag=1;
if(flag) cout<<"Impossible\n";
else cout<<"Possible\n";
}
int main() {
ios::sync_with_stdio(false);
// cin.tie(0);
int t=1;
// cin>>t;
// int ncase=1;
while(t--)
Test();
}
/*
1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End
*/
C - Hide and Seek
题解:因为只能移动到相邻位置,并且只能移动一次,在所有对中,只有三种情况满足题意,即:(x,x-1) (x,x) (x,x+1); 然后check 这三种情况是否满足题意
对(x,x-1),以下三种情况满足任意一种就可以使答案加1:
若不存在 x 这个位置,可以一直停到x这个点 不移动 就可以满足题意,答案就加1;
若不存在 x-1 这个位置,则可以一开始就从x位置移动到 x-1 就可以满足题意,答案就加1;
若x和x-1都存在,则第一个 x 后面的位置都没有x-1,答案就加1,这里简单证明一下:因为一开始停在 x点,最优的方案是在即将到达x的时候移动到 x-1 ,然后就不能移动了,在这之后如果后面还存在 x-1 的话,就不符合题意。
对(x,x) 只有数组中不存在x的时候这一对才有贡献
对(x,x+1) 考虑方式跟对(x,x-1)一样;
还要注意一点,当x=1时,没有对(x,x-1),当x=n时,没有对(x,x-1);,详细见代码。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000010;
int st[N],en[N];//st[i]表示i第一次出现的位置,en[i]数组代表i最后一次出现的位置
void Test(){
int n,k;
cin>>n>>k;
for(int i=1;i<=k;i++){
int x;
cin>>x;
if(st[x]==0) st[x]=i;
en[x]=i;
}
int cnt=0;
for(int i=1;i<=n;i++){
if(st[i]==0) cnt++;//判断对(x,x)
int x=st[i];
int y=en[i-1];
if(i>1)
if(y<=x||x==0||y==0) cnt++;//判断对(x,x-1)
y=en[i+1];
if(i<n)
if(y<=x||x==0||y==0) cnt++;//判断对(x,x+1)
}
cout<<cnt;
}
int main() {
ios::sync_with_stdio(false);
// cin.tie(0);
int t=1;
// cin>>t;
// int ncase=1;
while(t--)
Test();
}
/*
1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End
*/
D - Chladni Figure
题解:因为有 n 个位置 所以要想旋转k个位置后还与原图像重合,就相当于把原图形上的点移动k个位置,所有的点的连线情况与原图形相同,因为所有的点都是移动k个位置,所以所有满足题意的k必须是n的因子(可以手动模拟一下) 直接暴力check n的所有因子是否满足题意。假设x是n的因子 在check的x时候 可以把n个点全都逆时针移动x位,判断是否与原图形相同,就是判断所有点的连线情况,为了方便判断,可以把边的点按从小到大排序(相当于离散化),直接判断两个序列是否完全相同,若完全相同,就符合题意 。
因为判断的方法有很多种,也可以是vector储存,判断是可以直接判断v1==v2,但是当时想着时间复杂度比较大,就没有采用
详细见代码
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000010;
int prime[N];
bool st[N];
struct Node {
int a,b;
}p[N],q[N];
bool cmp(Node a,Node b){
if(a.a!=b.a) return a.a<b.a;
return a.b<b.b;
}
void Test(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>p[i].a>>p[i].b;
if(p[i].a>p[i].b) swap(p[i].a,p[i].b);//把原序列也排序,方便判断
}
sort(p+1,p+1+m,cmp);//对与对中也按从小到大,就是为了方便判断
for(int i=1;i<n;i++){
if(!(n%i==0)) continue;
for(int j=1;j<=m;j++) {
int x=p[j].a-i,y=p[j].b-i;//移动k各单位
if(x<=0) x=n+x;
if(y<=0) y=n+y;
if(x>y) swap(x,y);
q[j]={x,y};
}
sort(q+1,q+1+m,cmp);//也是离散化
int flag=0;
for(int j=1;j<=m;j++)
if(p[j].a!=q[j].a||p[j].b!=q[j].b) flag=1;
if(!flag) {//若两个序列全部相同,则符合答案
// cout<<i<<"\n";
cout<<"Yes";
return ;
}
}
cout<<"No\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t=1;
// cin>>t;
// int ncase=1;
while(t--)
Test();
}
/*
1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End
*/