T1 F
解题思路
由于 a 和 b 有一一对应的关系,因此实际上可能的答案只有 n 种。
对于每一种可能的答案可以直接扫一遍 a 数组看是否在 b 数组中是否一一匹配。
可以用 Hash 表,map 或者是 multiset 来维护。。
code
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=2e3+10;
int n,top,sta[N*N],a[N],b[N],s[N];
unordered_multiset<int> res;
bool check(int temp)
{
res.clear(); for(int i=1;i<=n;i++) res.insert(b[i]);
for(int i=1;i<=n;i++)
{
int num=temp^a[i];
if(res.find(num)==res.end()) return false;
res.erase(res.find(num));
}
return true;
}
signed main()
{
freopen("f.in","r",stdin); freopen("f.out","w",stdout);
n=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++) b[i]=read();
for(int i=1;i<=n;i++)
if(check(a[1]^b[i]))sta[++top]=a[1]^b[i];
sort(sta+1,sta+top+1); top=unique(sta+1,sta+top+1)-sta-1;
printf("%lld\n",top);
for(int i=1;i<=top;i++) printf("%lld\n",sta[i]);
return 0;
}
T2 S
解题思路
然而我只会模拟,正着扫是 10pts ,反着扫就是 50pts ,一结合就 60pts,然而我只有 10pts 。
正解是 DP ,对于同一种颜色内部的顺序肯定是不会改变的,于是假设位置在 \(i\) 的颜色最后的位置是 \(j\) 那么交换次数就是 \(j-i-相同颜色个数\) 。
DP 过程就是构建序列了 设 \(f_{i,j,k,0/1/2}\) 表示前 \(i\) 个有 \(j\) 个 R , \(k\) 个 G 最后结尾是什么答案。
那么发现可以滚掉一位,并且当前 Y 个数也可以算出来,转移即可。
code
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=410,INF=0x3f3f3f3f3f3f3f3f;
int n,ans=INF,s[N],f[2][N][N][3],cnt[3][N];
char ch[N];
vector<int> v[3];
signed main()
{
freopen("s.in","r",stdin); freopen("s.out","w",stdout);
n=read(); scanf("%s",ch+1); memset(f,0x3f,sizeof(f));
for(int i=0;i<=2;i++) v[i].push_back(0);
for(int i=1;i<=n;i++)
{
for(int j=0;j<=2;j++) cnt[j][i]=cnt[j][i-1];
if(ch[i]=='G') s[i]=1,cnt[1][i]++;
else if(ch[i]=='Y') s[i]=2,cnt[2][i]++;
else cnt[0][i]++; v[s[i]].push_back(i);
}
for(int i=0;i<=2;i++) if(cnt[i][n]>(n+1)/2) printf("-1"),exit(0);
if(cnt[0][n]) f[1][1][0][0]=0;
if(cnt[1][n]) f[1][0][1][1]=0;
if(cnt[2][n]) f[1][0][0][2]=0;
for(int i=1,mxa,mxb;i<n;i++)
{
for(int j=0;j<=cnt[0][n];j++)
for(int k=0;k<=cnt[1][n];k++)
fill(f[(i&1)^1][j][k]+0,f[(i&1)^1][j][k]+3,INF);
mxa=min(i,cnt[0][n]);
for(int j=0;j<=mxa;j++)
{
mxb=min(i-j,cnt[1][n]);
for(int k=0;k<=mxb;k++)
{
int p=i-j-k; if(p<0) continue;
for(int pos=0;pos<=2;pos++)
{
if(f[i&1][j][k][pos]==INF) continue;
if(pos&&j<cnt[0][n]) f[(i&1)^1][j+1][k][0]=min(f[(i&1)^1][j+1][k][0],f[i&1][j][k][pos]+max(0ll,k-cnt[1][v[0][j+1]])+max(0ll,p-cnt[2][v[0][j+1]]));
if(pos!=1&&k<cnt[1][n]) f[(i&1)^1][j][k+1][1]=min(f[(i&1)^1][j][k+1][1],f[i&1][j][k][pos]+max(0ll,j-cnt[0][v[1][k+1]])+max(0ll,p-cnt[2][v[1][k+1]]));
if(pos!=2&&p<cnt[2][n]) f[(i&1)^1][j][k][2]=min(f[(i&1)^1][j][k][2],f[i&1][j][k][pos]+max(0ll,j-cnt[0][v[2][p+1]])+max(0ll,k-cnt[1][v[2][p+1]]));
}
}
}
}
for(int i=0;i<=2;i++) ans=min(ans,f[n&1][cnt[0][n]][cnt[1][n]][i]);
printf("%lld",ans);
return 0;
}
T3 Y
解题思路
code
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e6+10,mod=1e9+7;
int n,s[N],f[N][2],inv2,inv6;
int power(int x,int y,int p=mod)
{
int temp=1;
while(y)
{
if(y&1) temp=temp*x%p;
x=x*x%p; y>>=1;
}
return temp;
}
int g1(int x){return x%=mod,x*(x+1)%mod*inv2%mod;}
int g2(int x){return x%=mod,x*(x+1)%mod*(2*x+1)%mod*inv6%mod;}
int solve(int base,int lim)
{
memset(f,0,sizeof(f)); f[1][0]=base; f[1][1]=base^1;
for(int i=1;i<=n;i++)
{
int num=s[i]-lim;
f[i+1][0]=(f[i+1][0]+f[i][0]*g1(num)%mod+f[i][1]*(num+1)%mod)%mod;
num+=lim; f[i+1][1]=(f[i+1][1]+f[i][0]*(num*g1(num)%mod-g2(num)+mod)%mod+f[i][1]*g1(num)%mod)%mod;
}
return f[n+1][base^1];
}
signed main()
{
freopen("y.in","r",stdin); freopen("y.out","w",stdout);
n=read(); inv2=power(2,mod-2); inv6=power(6,mod-2);
for(int i=1;i<=n;i++) s[i]=read();
printf("%lld",(solve(1,0)+solve(0,0)-solve(1,1)-solve(0,1)+2*mod)%mod);
return 0;
}
T4 O
解题思路
假作法,思路来自 zxb (数据是真的水,几乎都是单调递增的。。)
维护一个由栈底到栈顶单调递减的栈,每次暴扫单调栈,记录下当前的火苗会在哪一个时刻变化。
然后每一时刻直接暴力修改,树状数组维护加和即可。
code
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=2e5+10;
int n,m,pos=1,top,sta[N],s[N],ans[N];
vector< pair<int,int> > v[N];
struct Node{int id,t,l,r;}q[N];
struct BIT
{
int tre[N];
inline int lowbit(register int x){return x&(-x);}
inline void insert(register int x,register int val){for(register int i=x;i<=n;i+=lowbit(i))tre[i]+=val;}
inline int query(register int x){register int sum=0;for(register int i=x;i;i-=lowbit(i))sum+=tre[i];return sum;}
inline int query(register int l,register int r){return query(r)-query(l-1);}
}T;
bool comp(Node x,Node y){return x.t<y.t;}
signed main()
{
freopen("o.in","r",stdin); freopen("o.out","w",stdout);
n=read(); m=read();
for(register int i=1;i<=n;i++)
{
s[i]=read(); T.insert(i,s[i]);
while(top&&s[sta[top]]<=s[i]) top--;
for(register int j=1;j<=top;j++) v[i-sta[j]].push_back(make_pair(i,s[sta[j]]));
sta[++top]=i;
}
for(register int i=1,t,l,r;i<=m;i++) t=read(),l=read(),r=read(),q[i]=(Node){i,min(t,n),l,r}; sort(q+1,q+m+1,comp);
for(register int i=1;i<=n&&pos<=m;i++)
{
for(register int j=0;j<v[i].size();j++) T.insert(v[i][j].first,v[i][j].second-s[v[i][j].first]),s[v[i][j].first]=v[i][j].second;
while(pos<=m&&q[pos].t==i) ans[q[pos].id]=T.query(q[pos].l,q[pos].r),pos++;
}
for(register int i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}