Preface
有懶狗上週日的比賽拖到這週日才寫部落格,我不說是誰
這場比賽的時候因為 C 陣列沒開兩倍卡了 1h 最後寫對拍才看出來,直接心態爆炸導致 D 沒寫完掉大分
A. Question Marks
簽到
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=405;
int t,n; char s[N];
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
scanf("%d%s",&n,s+1);
int c[4]={0,0,0,0},ans=0;
for (RI i=1;i<=4*n;++i)
if (s[i]!='?') ++c[s[i]-'A'];
for (RI i=0;i<4;++i) ans+=min(c[i],n);
printf("%d\n",ans);
}
return 0;
}
B. Parity and Sum
注意到偶數與奇數的和依然為奇數,因此我們的策略總是把所有偶數變成奇數
拿出最大的奇數,從小到大和所有偶數比較,能操作就吸收這個偶數得到更大的奇數;否則直接找一個奇數和最大的偶數操作後得到一個最大的數,這個數一定可以和所有偶數進行操作
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=200005;
int t,n,a[N];
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
scanf("%d",&n); vector <int> odd,even;
for (RI i=1;i<=n;++i)
{
scanf("%d",&a[i]);
if (a[i]%2==1) odd.push_back(a[i]); else even.push_back(a[i]);
}
if (odd.empty()||even.empty()) { puts("0"); continue; }
sort(odd.begin(),odd.end());
sort(even.begin(),even.end());
int flag=0; LL cur=odd.back();
for (auto x:even) if (cur<x) { flag=1; break; } else cur+=x;
printf("%d\n",(int)even.size()+flag);
}
return 0;
}
C. Light Switches
不難發現燈的狀態以 \(2k\) 為週期變化,因此很容易想到把所有 \(t_i\) 投射到 \([0,2k-1]\) 的陣列上
此時我們需要找到一個長為 \(k\) 的區間 \([l,r]\) 使得其包含所有的數,注意這個區間是在模意義下的可以跨過末尾
最後答案為最小的 \(T\equiv r\pmod {2k}\),且所有的 \(t_i\le T\),簡單列舉即可
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=200005;
int t,n,k,a[N],c[N*2];
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
scanf("%d%d",&n,&k);
for (RI i=0;i<2*k;++i) c[i]=-1;
for (RI i=1;i<=n;++i)
scanf("%d",&a[i]),c[a[i]%(2*k)]=max(c[a[i]%(2*k)],a[i]);
vector <int> pos;
for (RI i=0;i<2*k;++i)
if (c[i]!=-1) pos.push_back(i);
if (pos.size()==1) { printf("%d\n",c[pos[0]]); continue; }
bool flag=0;
for (RI i=0;i<pos.size()-1;++i)
{
int l=pos[i+1],r=2*k+pos[i];
if (r-l<k)
{
int ans=0; for (auto x:pos)
if (x>=l) ans=max(ans,c[x]+r-x); else ans=max(ans,c[x]+r-2*k-x);
printf("%d\n",ans); flag=1; break;
}
}
if (!flag)
{
int l=pos[0],r=pos.back();
if (r-l<k)
{
int ans=0; for (auto x:pos)
ans=max(ans,c[x]+r-x);
printf("%d\n",ans); flag=1;
}
}
if (!flag) puts("-1");
}
return 0;
}
D. Med-imize
中位數的處理套路就是二分答案 \(x\),然後將 \(\ge x\) 的數置為 \(1\),\(<x\) 的數置為 \(0\)(置為 \(-1\) 也行),最後就是要使得留下的數的和大於某個定值
假設最後留下了 \(R\) 個數,觀察這些數需要滿足什麼限制,手玩後發現它們下標對 \(k\) 取模的值從左到右一定為 \(1,2,\dots,k\)
因此很容易想到 DP,令 \(f_{i}\) 表示處理了前 \(i\) 個數,且最後選的數下標模 \(k\) 的值和 \(i\bmod k\) 相同的最大權值和,轉移顯然
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=500005;
int t,n,k,rem,a[N],f[N];
inline int calc(CI lim)
{
int ret=0; for (RI i=1;i<=n;++i)
{
if ((i-1)%k+1>rem) { f[i]=0; continue; }
if ((i-1)%k==0)
{
f[i]=(a[i]>=lim);
if (i>=k) f[i]=max(f[i],f[i-k]);
}else
{
f[i]=f[i-1]+(a[i]>=lim);
if (i>=k) f[i]=max(f[i],f[i-k]);
}
ret=max(ret,f[i]);
}
return ret;
}
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
scanf("%d%d",&n,&k);
for (RI i=1;i<=n;++i) scanf("%d",&a[i]);
if (n<=k)
{
sort(a+1,a+n+1);
printf("%d\n",a[(n+1)/2]);
continue;
}
rem=n%k; if (rem==0) rem+=k;
int l=1,r=1e9,mid,ret;
while (l<=r) if (calc(mid=l+r>>1)>=rem/2+1) ret=mid,l=mid+1; else r=mid-1;
printf("%d\n",ret);
}
return 0;
}
E. Xor-Grid Problem
觀察到核心性質後就不難的一個題
不妨給矩形多擴充套件一行一列,其中最後一行的數字代表這列所有數字的異或和;最後列的數字代表這行所有數字的異或和
此時不難發現每個操作等價於交換某一行和最後一行,以及交換某一列和最後一列
但我們最後計算答案時不考慮多出的這一行一列,因此需要在選出某行某列刪去後,將剩下的行列任意排布得到答案
不難發現行和列的貢獻可以分開計算,以行為例,任意兩行相鄰排布的貢獻就是它們對應列(去掉被刪除的列後)上元素差的絕對值和
這形成了一個類似哈密頓路徑的問題,可以簡單狀壓 DP 解決,最後將刪去某行某列的答案合併即可
認為 \(n,m\) 同階,總複雜度 \(O(2^n\times n^3)\)
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=16,INF=1e9;
int t,n,m,a[N][N],dr[N][N],dc[N][N],R[N][N],C[N][N],f[1<<N][N];
inline void solve(int d[N][N],CI n)
{
for (RI i=0;i<(1<<n+1);++i)
for (RI j=0;j<=n;++j) f[i][j]=INF;
for (RI i=0;i<=n;++i) f[1<<i][i]=0;
for (RI mask=0;mask<(1<<n+1);++mask)
for (RI i=0;i<=n;++i) if ((mask>>i)&1)
for (RI j=0;j<=n;++j) if (!((mask>>j)&1))
f[mask|(1<<j)][j]=min(f[mask|(1<<j)][j],f[mask][i]+d[i][j]);
}
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
scanf("%d%d",&n,&m);
for (RI i=0;i<=n;++i) a[i][m]=0;
for (RI j=0;j<=m;++j) a[n][j]=0;
for (RI i=0;i<n;++i) for (RI j=0;j<m;++j)
scanf("%d",&a[i][j]),a[i][m]^=a[i][j],a[n][j]^=a[i][j];
for (RI i=0;i<n;++i) a[n][m]^=a[i][m];
for (RI rmv_c=0;rmv_c<=m;++rmv_c)
{
for (RI i=0;i<=n;++i) for (RI j=0;j<=n;++j)
{
if (i==j) continue; dr[i][j]=0;
for (RI k=0;k<=m;++k)
if (k!=rmv_c) dr[i][j]+=abs(a[i][k]-a[j][k]);
}
solve(dr,n);
for (RI i=0;i<=n;++i)
{
R[i][rmv_c]=INF; int mask=((1<<n+1)-1)^(1<<i);
for (RI j=0;j<=n;++j)
if ((mask>>j)&1) R[i][rmv_c]=min(R[i][rmv_c],f[mask][j]);
}
}
for (RI rmv_r=0;rmv_r<=n;++rmv_r)
{
for (RI i=0;i<=m;++i) for (RI j=0;j<=m;++j)
{
if (i==j) continue; dc[i][j]=0;
for (RI k=0;k<=n;++k)
if (k!=rmv_r) dc[i][j]+=abs(a[k][i]-a[k][j]);
}
solve(dc,m);
for (RI i=0;i<=m;++i)
{
C[rmv_r][i]=INF; int mask=((1<<m+1)-1)^(1<<i);
for (RI j=0;j<=m;++j)
if ((mask>>j)&1) C[rmv_r][i]=min(C[rmv_r][i],f[mask][j]);
}
}
int ans=INF; for (RI i=0;i<=n;++i) for (RI j=0;j<=m;++j)
ans=min(ans,R[i][j]+C[i][j]); printf("%d\n",ans);
}
return 0;
}
F1. Dyn-scripted Robot (Easy Version)
感覺比 D,E 都簡單,算是個經典套路題
對於這類反射類問題一個經典的處理就是不改變機器人的移動方向,而是將整個外框映象一下,這樣就不涉及修改操作序列了
手玩下會發現當機器人走到 \((x,y)\) 時,在原矩形中的位置相當於 \((x\bmod 2w,y\bmod 2h)\)
因此這題很容易求解,我們先求出進行一整個序列的操作後坐標的偏移量 \(\Delta x,\Delta y\),然後列舉之前進行了 \(i\in[0,k-1]\) 次完整的操作
要回到 \((0,0)\) 等價於在某個位置的偏移量為 \((-i\times \Delta x,-i\times \Delta y)\)(模意義下),用 map
統計下即可
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=1e6+5;
int t,n,k,w,h; char s[N];
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
scanf("%d%d%d%d%s",&n,&k,&w,&h,s+1);
map <pi,int> rst; int x=0,y=0;
for (RI i=1;i<=n;++i)
{
switch (s[i])
{
case 'U': ++y; break;
case 'D': --y; break;
case 'R': ++x; break;
case 'L': --x; break;
}
x=(x%(2*w)+2*w)%(2*w);
y=(y%(2*h)+2*h)%(2*h);
++rst[{x,y}];
}
LL ans=0; for (RI i=0;i<k;++i)
{
int dx=(-1LL*i*x%(2*w)+2*w)%(2*w);
int dy=(-1LL*i*y%(2*h)+2*h)%(2*h);
ans+=rst[{dx,dy}];
}
printf("%lld\n",ans);
}
return 0;
}
Postscript
感覺最近不管什麼比賽只要不順心就容易紅溫犯病,明明已經算是老登了心態還是一如既往的爛
今晚還有 Div1+2,週末還要去北京打百度之星的決賽,希望別暴斃地太難看了吧