蓝题都不会做
agc059
My Last ABC Problem
首先一次操作显然最多可以让相邻不同元素对 − 2 -2 −2。
考虑选取 A A A作为特征元素,那么会分成若干段 B C BC BC交错的区间,如果长度为奇数那么可以先全部变成 B / C B/C B/C再翻过来;如果长度为偶数那么可以看成长度为 2 2 2的段。对于两个长度为 2 2 2的段可以合并在一起,最后如果剩的长度为 4 4 4就再操作 2 2 2次即可。
基于上述观察,我们在询问区间的开头和结尾添一个字母(表示整个区间最终变成的结果),设此时序列长度为 L L L,那么 ⌈ L − 1 2 ⌉ \lceil\frac{L-1}{2}\rceil ⌈2L−1⌉就是答案。
#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
int n,m;
int a[100005],p[100005],cnt;
string s;
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>m>>s;
for(int i=0;i<s.size();i++){
int j=i;while(j+1<s.size()&&s[j+1]==s[i])j++;
i=j,a[++cnt]=s[i]-'A',p[cnt]=j+1;
}
for(int i=1;i<=m;i++){
int l,r;cin>>l>>r,l=lower_bound(p+1,p+1+cnt,l)-p,r=lower_bound(p+1,p+1+cnt,r)-p;
if(l==r)cout<<0<<"\n";
else {
if(a[l]==a[r])cout<<(r-l+1)/2<<"\n";
else cout<<(r-l+2)/2<<"\n";
}
}
}
Arrange Your Balls
2 hard 4 me
一个简单的思路是,首先把相同颜色的球排在一起,这样答案是颜色数目 k k k。
如果一个颜色段很小,那么可以合并到大的颜色块当中,并且只占一个间隙。
基于上述观察,我们可以贪心的取出任意一个颜色块,然后将其他颜色块插入到它的一个间隙中(这个颜色产生的贡献恰为 1 1 1),这样如果最后剩的颜色块数目 ≤ 2 \le 2 ≤2那么答案是 k − 1 k-1 k−1。
模拟即可。
#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
int T,n,r,id[200005],c[200005],nxt[200005],vis[200005],res[200005];
int cnt,cnt2;
pair<int,int>s[200005],s2[200005];
int main(){
// freopen("data.in","r",stdin);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--){
cin>>n;for(int i=1;i<=n;i++)c[i]=nxt[i]=vis[i]=0;
for(int i=1;i<=n;i++){
int x;cin>>x,c[x]++;
}r=cnt=cnt2=0;
for(int i=1;i<=n;i++){
if(!c[i])continue;
for(int j=1;j<=c[i];j++)id[j]=++r,res[r]=i;
for(int j=1;j<c[i];j++)nxt[id[j]]=id[j+1];
if(c[i]>1){
for(int j=1;j<c[i];j++){
s[++cnt]={id[j],id[j+1]};
}
while(cnt2&&cnt){
nxt[s[cnt].fi]=s2[cnt2].fi;
nxt[s2[cnt2].se]=s[cnt].se;
cnt2--,cnt--;
}
s2[++cnt2]={id[1],id[c[i]]};
}
else{
if(cnt){
nxt[s[cnt].fi]=id[1],nxt[id[c[i]]]=s[cnt].se;
cnt--;
}
else {
s2[++cnt2]={id[1],id[c[i]]};
}
}
}
for(int i=1;i<cnt2;i++){
nxt[s2[i].se]=s2[i+1].fi;
}
for(int i=1;i<=n;i++){
vis[nxt[i]]=1;
}
int rt=0;
for(int i=1;i<=n;i++){
if(!vis[i])rt=i;
}assert(rt);
while(rt){
cout<<res[rt]<<' ',rt=nxt[rt];
}cout<<"\n";
}
}
Guessing Permutation for as Long as Possible
数数题令人头疼
可以把过程想象为在一张图上每次加一条有向边 ( u , v ) (u,v) (u,v),如果存在路径 u ′ → v ′ u'\to v' u′→v′并且 ( u ′ , v ′ ) ≠ E (u',v')\ne E (u′,v′)=E那么就不合法。
然后考虑所有三元导出子图,如果 ( X , Y ) (X,Y) (X,Y), ( Y , Z ) (Y,Z) (Y,Z)的出现时刻比 ( X , Z ) (X,Z) (X,Z)早,并且满足 X > Y > Z X>Y>Z X>Y>Z,那么就可以确定出 X > Z X>Z X>Z,故而不合法。
直接数原排列 p p p复杂度 O ( 2 n ) O(2^n) O(2n)。既然原排列不好数,那么我们考虑每个原排列一定对应唯一一个完全图,其中每条边的颜色表示两个元素之间的大小关系。
那么我们考虑上述条件相当于 ( X , Y ) , ( Y , Z ) (X,Y),(Y,Z) (X,Y),(Y,Z)的颜色必须不同,那么我们构造一个含 n 2 n^2 n2个点的图,如果不存在二分图匹配那么答案是 0 0 0。否则对于一个连通图有两种染色方案,同时对于一个合法的染色方案,它所对应的图一定不存在环,因此存在拓扑排序,也就存在一个合法的 p p p。综上,我们只要数合法的染色方案即可,设连通块数目为 k k k,则总方案数为 2 k 2^k 2k。
#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
const int mod=1e9+7;
int n,m,id[405][405],a[405][405];
int c[405*405];
vector<pair<int,int>>g[405*405];
void add(int x,int y,int z){
g[x].pb({y,z}),g[y].pb({x,z});
}
void dfs(int u,int topf){
c[u]=topf;
for(auto v:g[u]){
if(c[v.fi]==-1)dfs(v.fi,topf^v.se);
else if(c[v.fi]!=(topf^v.se)){
cout<<0;
exit(0);
}
}
}
int main(){
// freopen("data.in","r",stdin);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
id[i][j]=id[j][i]=++m;
}
}
for(int i=1;i<=m;i++){
int x,y;cin>>x>>y,a[x][y]=a[y][x]=i;
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
for(int k=j+1;k<=n;k++){
if(a[j][i]<a[i][k]&&a[j][k]<a[i][k]){
add(id[j][i],id[j][k],(i<j)^(j>k));
}
else if(a[k][i]<a[i][j]&&a[k][j]<a[i][j]){
add(id[k][i],id[k][j],(i<k)^(k>j));
}
else if(a[i][j]<a[j][k]&&a[i][k]<a[j][k]){
add(id[i][j],id[i][k],(j<i)^(i>k));
}
}
}
}memset(c,-1,sizeof c);ll res=1;
for(int i=1;i<=m;i++){
if(c[i]==-1){
dfs(i,0),res=res*2%mod;
}
}cout<<res;
}
Grid 3-coloring
这个D实在是不可做啊
我们考虑构造一个与 c c c同余的矩阵 a a a,并且满足 a a a矩阵中相邻位置数字只差恰好为 1 1 1
容易发现,至少存在一个合法的 a a a矩阵与 c c c对应(考虑从左上角开始构造,容易验证不会产生矛盾),如果规定矩阵的数字最小的话那么不难猜想 a a a, c c c矩阵形成一一对应关系。
不妨假设 a 1 , 1 = c 1 , 1 a_{1,1}=c_{1,1} a1,1=c1,1,然后将 4 n − 4 4n-4 4n−4个变量全部确定出来。如果存在矛盾那么显然无解。
然后我们得到了有解的必要条件:
1.1 1.1 1.1对于任意 2 ≤ i ≤ n − 1 2\le i\le n-1 2≤i≤n−1,满足 ∣ a i , 1 − a i , n ∣ < n |a_{i,1}-a_{i,n}|<n ∣ai,1−ai,n∣<n 并且 ∣ a 1 , i − a n , i ∣ < n |a_{1,i}-a_{n,i}|<n ∣a1,i−an,i∣<n
考虑给出构造或者直接走人 :
a
i
,
j
=
max
(
{
a
i
,
1
−
(
j
−
1
)
,
a
i
,
n
−
(
n
−
j
)
,
a
1
,
j
−
(
i
−
1
)
,
a
n
,
j
−
(
n
−
i
)
}
)
a_{i,j}=\max(\{a_{i,1}-(j-1),a_{i,n}-(n-j),a_{1,j}-(i-1),a_{n,j}-(n-i)\})
ai,j=max({ai,1−(j−1),ai,n−(n−j),a1,j−(i−1),an,j−(n−i)})
这个式子怎么来看呢,首先我们证明 ( n − 2 ) × ( n − 2 ) (n-2)\times (n-2) (n−2)×(n−2)矩阵中相邻位置的差恰好为 1 1 1。
证明非常巧妙,考虑手玩样例,我们会发现 { a i , 1 − ( j − 1 ) , a i , n − ( n − j ) , a 1 , j − ( i − 1 ) , a n , j − ( n − i ) } \{a_{i,1}-(j-1),a_{i,n}-(n-j),a_{1,j}-(i-1),a_{n,j}-(n-i)\} {ai,1−(j−1),ai,n−(n−j),a1,j−(i−1),an,j−(n−i)}的奇偶性相同,那么相邻位置的每一项都相差 1 1 1,这样最大值相差最多是 1 1 1,又因为奇偶性不同,因此恰好相差 1 1 1。
然后考虑边界的取值。假设 ∣ a i , 1 − a i , 2 ∣ ≠ 1 |a_{i,1}-a_{i,2}|\ne 1 ∣ai,1−ai,2∣=1(对于其他情况将矩形旋转即可),那么 a i , 2 ≥ a i , 1 + 3 a_{i,2}\ge a_{i,1}+3 ai,2≥ai,1+3,如果 a i , 2 = a i , n − ( n − 2 ) a_{i,2}=a_{i,n}-(n-2) ai,2=ai,n−(n−2)那么 a i , n = a i , 1 + 1 a_{i,n}=a_{i,1}+1 ai,n=ai,1+1与条件矛盾;如果 a i , 2 = a 1 , 2 − ( i − 1 ) a_{i,2}=a_{1,2}-(i-1) ai,2=a1,2−(i−1)那么 a 1 , 2 ≥ a i , 1 + i + 2 a_{1,2}\ge a_{i,1}+i+2 a1,2≥ai,1+i+2并且 a 1 , 1 ≤ a i , 1 + i − 1 a_{1,1}\le a_{i,1}+i-1 a1,1≤ai,1+i−1,故而 ∣ a 1 , 2 − a 1 , 1 ∣ ≥ 3 |a_{1,2}-a_{1,1}|\ge 3 ∣a1,2−a1,1∣≥3与条件矛盾;如果 a i , 2 = a n , 2 − ( n − i ) a_{i,2}=a_{n,2}-(n-i) ai,2=an,2−(n−i)那么证明类似。
综上,我们证明了上述构造的合法性。复杂度 O ( n ) O(n) O(n)。
#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
int T,n,a[1000005];
int b[1005][1005];
string s;
int solve(){
cin>>n>>s;a[1]=s[0]-'0';
for(int i=2;i<=4*n-4;i++){
a[i]=s[i-1]-'0';if(a[i]%3==a[i-1]%3)return 0;
if((a[i-1]+1)%3==a[i]%3)a[i]=a[i-1]+1;
else a[i]=a[i-1]-1;
}
if(abs(a[1]-a[4*n-4])!=1)return 0;
for(int i=2,j=3*(n-1);i<n;i++,j--){
if(abs(a[i]-a[j])>=n)return 0;
}
for(int i=n+1,j=4*n-4;i<2*n-1;i++,j--){
if(abs(a[i]-a[j])>=n)return 0;
}return 1;
}
void print(){
for(int i=1;i<n;i++)b[1][i]=a[i];
for(int i=1;i<n;i++)b[i][n]=a[i+n-1];
for(int i=1;i<n;i++)b[n][n-i+1]=a[i+2*(n-1)];
for(int i=1;i<n;i++)b[n-i+1][1]=a[i+3*(n-1)];
for(int i=2;i<n;i++){
for(int j=2;j<n;j++){
b[i][j]=max({b[i][1]-(j-1),b[i][n]-(n-j),b[1][j]-(i-1),b[n][j]-(n-i)});
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<b[i][j]<<' ';
}cout<<"\n";
}
}
int main(){
freopen("data.in","r",stdin);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--){
cout<<(solve()?"YES":"NO")<<"\n";
print();
}
}