A
#include <bits/stdc++.h>
using namespace std;
int t,n,m;
signed main() {
ios::sync_with_stdio(false);
cin>>t;
while(t--) {
cin>>n>>m;
if(n%m==0) puts("YES");
else puts("NO");
}
}
B
给定序列 (a),构造一个解,将它重新排序后,称为一个新的序列,使得 (j-i eq a_j-a_i)
排序后再翻转
#include <bits/stdc++.h>
using namespace std;
int t,n,a[105];
signed main() {
ios::sync_with_stdio(false);
cin>>t;
while(t--) {
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
reverse(a+1,a+n+1);
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
cout<<endl;
}
}
C
能否对一个初态都为 (0) 数组执行任意次操作,使他变成目标数组。第 (i) 次操作可以放弃,或者给某个元素加上 (k^i)
把 (k=1) 的特判掉,剩下的相当于一个进制分解判重
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 100;
const int lim = 1e16;
int t,n,k,a[N],u[N];
signed main() {
ios::sync_with_stdio(false);
cin>>t;
while(t--) {
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
if(k==1) {
puts("YES");
continue;
}
memset(u,0,sizeof u);
int fg=0;
for(int i=1;i<=n;i++) {
for(int j=0;j<=66;j++) {
if(a[i]%k==1) {
++u[j];
}
else if(a[i]%k>1) {
puts("NO");
goto AERR;
}
a[i]/=k;
}
}
for(int i=0;i<=66;i++) fg=max(fg,u[i]);
if(fg>1) puts("NO");
else puts("YES");
AERR:cout<<"";
}
}
D
求长度为 (n) 的序列 (a) 的个数:(a_i in [1,m]),存在且仅存在一对相同元素,存在 (p) 使得 (a[1...p]) 严格单增,(a[p...n]) 严格单调递减
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
int qpow(int p,int q) {
return (q&1?p:1) * (q?qpow(p*p%mod,q/2):1) % mod;
}
int frac(int p) {
int res = 1;
for(int i=1;i<=p;i++) res *= i, res %= mod;
return res;
}
int inv(int p) {
return qpow(p,mod-2);
}
signed main() {
int n,m;
cin>>n>>m;
int ans=frac(m)*inv(frac(n-1))%mod*inv(frac(m-n+1))%mod;
ans=ans*(n-2)%mod*qpow(2,n-3)%mod;
cout<<ans;
}
E
给定一个长度为 (n leq 500) 的数组 (a),元素均 (leq 1000),每次你可以找到 (i) 使得 (a[i]=a[i+1]),将它们替换成一个数 (a_i+1),求剩余数组长度的最小值
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 505;
int n,a[N],f[N][N],g[N][N];
signed main() {
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=-1;
for(int i=1;i<=n;i++) f[i][i]=a[i];
for(int l=1;l<n;l++) {
for(int i=1;i+l<=n;i++) {
int j=i+l;
for(int k=i;k<j;k++) {
if(f[i][k]>0 && f[k+1][j]>0 && f[i][k]==f[k+1][j]) {
f[i][j]=f[i][k]+1;
}
}
}
}
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) {
if(f[i][j]==-1) g[i][j]=1e9;
else g[i][j]=1;
}
for(int l=1;l<n;l++) {
for(int i=1;i+l<=n;i++) {
int j=i+l;
for(int k=i;k<j;k++) {
g[i][j]=min(g[i][j],g[i][k]+g[k+1][j]);
}
}
}
cout<<g[1][n];
}
F
有 (n) 个数,甲乙两人轮流操作,甲先手,每次操作有三个选项
- 将一个 (>0) 的数 (-x)
- 将一个 (>0) 的数 (-y)
- 将一个 (>0) 的数 (-z)
如果操作后这个数 (<0) 则自动变为 (0)
对于一个数,如果上次对这个数操作是第二种,那么这次就不能操作第二种,如果上次对这个数操作是第三种,那么这次就不能操作第三种
不能操作的人输,问甲先手,第一步有多少种办法使得自己必胜
Solution
首先可以将各个 (a_i) 分开来考虑,最后将结果异或起来就是局面的 SG 值
设 (SG(x,c)) 表示在这个数为 (x),上次操作为 (c) 时的 SG 值,那么转移很显然是
由于 (x,y,z) 很小,所以 (SG) 函数一定有一个很小的循环节
#include <bits/stdc++.h>
using namespace std;
#define int long long
int mex(set<int> s) {
for(int i=0;i<=4;i++) if(s.find(i)==s.end()) return i;
}
int x,y,z;
namespace sg {
int sg[105][4];
int I,J;
int getsg(int t,int c) {
if(t<J) return sg[t][c];
return sg[J+(t-J)%(I-J)][c];
}
void clear() {
I=0; J=0;
memset(sg,0,sizeof sg);
}
void calc(int ai) {
for(int i=1;;i++) {
set<int> s;
s.insert(sg[max(0ll,i-x)][0]);
s.insert(sg[max(0ll,i-y)][1]);
s.insert(sg[max(0ll,i-z)][2]);
sg[i][0]=mex(s);
s.clear();
s.insert(sg[max(0ll,i-x)][0]);
s.insert(sg[max(0ll,i-z)][2]);
sg[i][1]=mex(s);
s.clear();
s.insert(sg[max(0ll,i-x)][0]);
s.insert(sg[max(0ll,i-y)][1]);
sg[i][2]=mex(s);
for(int j=4;j<i-4;j++) {
int fg=1;
for(int k=0;k<=4;k++) {
for(int u=0;u<3;u++) {
if(sg[j-k][u]!=sg[i-k][u]) fg=0;
}
}
if(fg) {
I=i;
J=j;
return;
}
}
}
}
}
int t,n,a[300005],ssg[300005][3],osg[300005];
signed main() {
ios::sync_with_stdio(false);
cin>>t;
while(t--) {
cin>>n>>x>>y>>z;
for(int i=1;i<=n;i++) cin>>a[i];
sg::clear();
sg::calc(0);
int sum=0;
for(int i=1;i<=n;i++) {
osg[i]=sg::getsg(a[i],0);
sum^=osg[i];
ssg[i][0]=sg::getsg(max(0ll,a[i]-x),0);
ssg[i][1]=sg::getsg(max(0ll,a[i]-y),1);
ssg[i][2]=sg::getsg(max(0ll,a[i]-z),2);
}
int ans=0;
for(int i=1;i<=n;i++) {
if((sum^osg[i]^ssg[i][0])==0) ++ans;
if((sum^osg[i]^ssg[i][1])==0) ++ans;
if((sum^osg[i]^ssg[i][2])==0) ++ans;
}
cout<<ans<<endl;
}
}
G
给定一个字符串集合 (S),需要计算打 (S) 中所有字符串花费的时间总和
打一个字符串的步骤如下:从一个空串开始;如果当前的字符串是 (t),你可以末尾拼接任意一个小写字母,花费 (1s)
你可以使用自动补全功能,设当前字符串是 (t),此时所有 (sin S) 会按照字典序展现出来,自动补全到第 (i) 个串需要 (is)
#include <bits/stdc++.h>
using namespace std;
const int inf=1e9;
const int N=1e+6+5;
struct node {
char c;
int nxt;
bool operator < (const node &b) const {
return c<b.c;
}
};
int n,m,q[N],tar[N],ans[N];
vector <node> g[N];
int dfs(int u,int c) {
int rk=0;
if(tar[u]) ans[u]=min(ans[u],c), ++rk;
for(int i=0;i<g[u].size();i++) {
int v=g[u][i].nxt;
ans[v]=ans[u]+1;
rk+=dfs(v,min(ans[v],c)+rk);
}
return rk;
}
signed main() {
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++) {
int t;
char c;
cin>>t>>c;
g[t].push_back({c,i});
}
for(int i=0;i<n;i++) sort(g[i].begin(),g[i].end());
cin>>m;
for(int i=1;i<=m;i++) {
cin>>q[i];
tar[q[i]]=1;
}
dfs(0,inf);
for(int i=1;i<=m;i++) cout<<ans[q[i]]<<" ";
}