Preface
這周開始晚課變得巨多,導致基本沒有時間自己寫題
眼看著這週五週六又有CF,趕緊把上週五的這場補了
這場感覺C有點詐騙了,我反正是去寫線段樹上二分了,不帶$\log $的做法還要動腦
A. Entertainment in MAC
簽到,可能的串就兩種,要麼保留原串;要麼reverse
後再拼接原串
#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;
int t,n; string a;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
ios::sync_with_stdio(false); cin.tie(0);
for (cin>>t;t;--t)
{
cin>>n>>a; string tmp=a;
reverse(tmp.begin(),tmp.end()); string b=tmp+a;
cout<<min(a,b)<<endl;
}
return 0;
}
B. Informatics in MAC
首先不難發現如果分多個區間合法,那麼合併其中若干個區間後亦然合法,因此只要考慮分成兩個區間的情況
從小到大列舉每個數,用它在原序列中出現的位置來更新分界點的可能取值,當出現某個未出現的數時則找到解
#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=100005;
int t,n,a[N],l[N],r[N];
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i; for (scanf("%d",&n),i=0;i<=n;++i) l[i]=n+1,r[i]=0;
for (i=1;i<=n;++i) scanf("%d",&a[i]),l[a[i]]=min(l[a[i]],i),r[a[i]]=max(r[a[i]],i);
int L=1,R=n-1; bool flag=0;
for (i=0;i<=n;++i)
{
if (l[i]>n)
{
flag=1; printf("2\n%d %d\n%d %d\n",1,L,L+1,n); break;
}
L=max(L,l[i]); R=min(R,r[i]-1);
if (L>R) break;
}
if (!flag) puts("-1");
}
return 0;
}
C. Messenger in MAC
首先一眼將二元組按照\(b_i\)排序,考慮當我們確定選取的下標位於區間\({L,R}\)時,後面的貢獻總是\(b_R-b_L\)
由於本題資料範圍允許\(O(n^2)\)列舉區間,因此確定端點後就是要在\([L+1,R-1]\)中找出最多數量的數使得它們的和小於某個值了
用權值線段樹隨便處理一下,詢問的話線上段樹上二分,總複雜度\(O(n^2\log n)\)
(PS:好像有基於單調性的\(O(n^2)\)DP做法,但懶得管了能過就行)
#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 int long long
#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=2005;
int t,n,m; pi p[N]; vector <int> rst;
class Segment_Tree
{
private:
int sz[N<<2],sum[N<<2];
public:
#define TN CI now=1,CI l=0,CI r=rst.size()-1
#define LS now<<1,l,mid
#define RS now<<1|1,mid+1,r
inline void init(TN)
{
sz[now]=sum[now]=0; if (l==r) return; int mid=l+r>>1; init(LS); init(RS);
}
inline void insert(CI pos,TN)
{
++sz[now]; sum[now]+=rst[pos]; if (l==r) return; int mid=l+r>>1;
if (pos<=mid) insert(pos,LS); else insert(pos,RS);
}
inline int query(CI lim,TN)
{
if (l==r) return min(sz[now],lim/rst[l]); int mid=l+r>>1;
if (lim<=sum[now<<1]) return query(lim,LS); else return sz[now<<1]+query(lim-sum[now<<1],RS);
}
#undef TN
#undef LS
#undef RS
}SEG;
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%lld",&t);t;--t)
{
RI i,j; rst.clear(); int ans=0;
for (scanf("%lld%lld",&n,&m),i=1;i<=n;++i)
scanf("%lld%lld",&p[i].se,&p[i].fi),rst.push_back(p[i].se);
sort(rst.begin(),rst.end()); rst.erase(unique(rst.begin(),rst.end()),rst.end());
for (i=1;i<=n;++i) if (p[i].se<=m) ans=1;
for (sort(p+1,p+n+1),i=1;i<n;++i)
{
if (p[i+1].fi-p[i].fi+p[i].se+p[i+1].se<=m) ans=max(ans,2LL);
for (SEG.init(),j=i+1;j<n;++j)
{
SEG.insert(lower_bound(rst.begin(),rst.end(),p[j].se)-rst.begin());
int tmp=p[j+1].fi-p[i].fi+p[i].se+p[j+1].se;
if (tmp<=m) ans=max(ans,2LL+SEG.query(m-tmp));
}
}
printf("%lld\n",ans);
}
return 0;
}
D. Exam in MAC
剛開始讀假題了感覺一點不可做,後面發現原來是又犯病了
考慮用容斥,所有二元組的總數為\(\frac{(c+1)\times (c+2)}{2}\),對於每個給定的\(s_i\),分別考慮\(y-x=s_i\)和\(y+x=s_i\)的二元組\((x,y)\)數量,顯然前者有\(c+1-s_i\)個,後者有\(\lfloor\frac{s_i}{2}\rfloor +1\)個
現在考慮要加回那些被統計了兩次的二元組數量,設存在二元組\((x,y)\)被統計了兩次,即\(M=y-x,N=y+x\)均在\(\{s_i\}\)中出現
注意到\(x=\frac{N-M}{2},y=\frac{N+M}{2}\),因此當\(M,N\)的奇偶性相同時,必然存在一組合法且唯一的\((x,y)\)與之對應
因此統計出\(\{s_i\}\)中奇/偶數個數\(odd,even\),答案再加上\(\frac{odd\times (odd+1)}{2}+\frac{even\times (even+1)}{2}\)即可
#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 int long long
#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;
int t,n,c,x;
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%lld",&t);t;--t)
{
RI i; int cnt[2]={0,0}; int dec=0;
for (scanf("%lld%lld",&n,&c),i=1;i<=n;++i)
scanf("%lld",&x),++cnt[x&1],dec+=(c+1-x)+(x/2+1);
printf("%lld\n",(c+2)*(c+1)/2LL-dec+(cnt[0]+1)*cnt[0]/2LL+(cnt[1]+1)*cnt[1]/2LL);
}
return 0;
}
E. Distance Learning Courses in MAC
經典二進位制+DS的題,為什麼感覺這類題目就是出不完呢
首先考慮如果每個數選擇沒有下界怎麼做,不妨考慮二進位制下每一位在區間中出現的次數
顯然如果出現\(0/1\)次那麼這位的取值肯定是確定的,如果出現\(>1\)次則必然可以透過將其中一個數這一位改為\(0\),然後將小於該位的全部取為\(0\),這樣一定是最優的
現在考慮加上下界的限制該怎麼做,不難發現這其實就是限制了某些位是不能用上述的方式修改的
具體地,我們找到\(x,y\)二進位制下最高且不同的位,則對於這個數來說,這一段字首的值就固定了,而後面部分可以隨便取
因此把每個數固定的部分拆出來後,剩下的部分就轉化為沒有下界的問題了,可以從高位到低位貪心處理
注意到或運算允許查詢的時候區間有重疊,因此可以直接拿個RMQ維護下固定部分的貢獻,而每一位出現的次數可以用字首和處理
總複雜度\(O((n+q)\log n)\)
#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,q,x,y,pfx[N][30];
namespace RMQ
{
int f[N][20],_log[N];
inline void init(void)
{
RI i,j; for (_log[0]=-1,i=1;i<=n;++i) _log[i]=_log[i>>1]+1;
for (j=1;(1<<j)<=n;++j) for (i=1;i+(1<<j)-1<=n;++i)
f[i][j]=f[i][j-1]|f[i+(1<<j-1)][j-1];
}
inline int query(CI l,CI r)
{
int k=_log[r-l+1]; return f[l][k]|f[r-(1<<k)+1][k];
}
};
using namespace RMQ;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%lld",&t);t;--t)
{
RI i,j; for (scanf("%d",&n),i=1;i<=n;++i)
{
scanf("%d%d",&x,&y);
if (x==y) f[i][0]=x,y=0; else
{
int k=__lg(x^y); f[i][0]=y;
y&=((1<<k+1)-1); f[i][0]^=y;
}
for (j=0;j<30;++j) pfx[i][j]=pfx[i-1][j]+((y>>j)&1);
}
for (init(),scanf("%d",&q),i=1;i<=q;++i)
{
scanf("%d%d",&x,&y); int ans=0,res=query(x,y);
for (j=29;j>=0;--j)
{
int bits=pfx[y][j]-pfx[x-1][j]+((res>>j)&1);
if (bits>1) { ans|=((1<<j+1)-1); break; }
else if (bits==1) ans|=(1<<j);
}
printf("%d%c",ans," \n"[i==q]);
}
}
return 0;
}
Postscript
最近事情好多的說……