签到,可以两倍字符串直接判断
#include
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N=5010,M=4e5+10;
const int INF=1e18;
const int mod=998244353;
// const int mod=1e9+7;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
void solve(){
int n,k;
cin>>n>>k;
k=min(k,7ll);
string s;
cin>>s;
s+=s;
s=" "+s;
vector<int> sum(2*n+1);
int ans=0;
for(int i=1;i<=2*n;i++){
sum[i]=sum[i-1];
if(i>=7&&s.substr(i-6,7)=="nanjing")sum[i]++;
if(i>=n&&i-n<=k)ans=max(ans,sum[i]-sum[i-n]);
}
cout<<ans<<"\n";
}
signed main(){
cin.tie(0)->sync_with_stdio(0);
int T=1;
cin>>T;
while(T--)solve();
return 0;
}
有三种情况:
#include
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N=5010,M=4e5+10;
const int INF=1e18;
const int mod=998244353;
// const int mod=1e9+7;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
void solve(){
int n,m,k;
cin>>n>>m>>k;
vector<int> vis(k+1),have(k+1),now(k+1);
map<PII,int> cnt;
for(int i=1;i<=n;i++){
int x;
cin>>x;
vis[x]=1;
}
int ans=0;
for(int i=1;i<=m;i++){
int a,b;
cin>>a>>b;
if(vis[a]&&vis[b])ans++;
else if(vis[a])have[b]++;
else if(vis[b])have[a]++;
else{
if(a<b)swap(a,b);
if(a!=b)cnt[{a,b}]++;
else have[a]++;
}
}
for(auto &[p,c]:cnt){
auto &[a,b]=p;
now[a]=max(now[a],have[a]+have[b]+c);
now[b]=max(now[b],have[a]+have[b]+c);
}
vector<int> tmp;
int res=0;
for(int i=1;i<=k;i++){
if(!vis[i])res=max(res,now[i]),tmp.push_back(have[i]);
}
sort(tmp.begin(),tmp.end(),greater<int>());
if(tmp.size()>=2)res=max(res,tmp[0]+tmp[1]);
else if(tmp.size())res=max(res,tmp[0]);
// cout<
cout<<ans+res<<"\n";
}
signed main(){
cin.tie(0)->sync_with_stdio(0);
int T=1;
cin>>T;
while(T--)solve();
return 0;
}
题意:
w个格子排成一排,n个红色,m个黑色,其余白色,可以放一条长度为k的板子,但
是不能覆盖黑色,问至少需要多少个板子覆盖所有红色,或说明不可能
思路:
直接贪心放,如果被黑色格子挡住了就需要左移,如果左移失败,则不可能
#include
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N=3010;
const int INF=1e18;
// const int mod=998244353;
const int mod=1e9+7;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
void solve(){
int n,m,k,w;
cin>>n>>m>>k>>w;
vector<int> a(n+1),b(m+1);
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=m;i++)cin>>b[i];
sort(a.begin()+1,a.end());
sort(b.begin()+1,b.end());
vector<array<int,2>> seg;
seg.push_back({0,0});
b.push_back(w+1);
for(int i=1;i<=n;i++){
if(seg.back()[1]>=a[i])continue;
int t=lower_bound(b.begin()+1,b.end(),a[i])-b.begin();
int len;
if(t==b.size())len=INF;
else len=b[t]-a[i];
seg.push_back({a[i],a[i]+k-1});
if(len>=k)continue;
int pp=k-len;
while(true){
int R=upper_bound(b.begin()+1,b.end(),seg.back()[0])-b.begin();
R--;
int x=seg.back()[0]-seg[seg.size()-2][1]-1;
if(x>=pp){
int left=seg.back()[0]-pp;
if(b[R]<left){
if(x==pp&&seg.size()!=2){
int tmp=seg.back()[1]-pp;
seg.pop_back();
seg.back()[1]=tmp;
}
else seg.back()[0]-=pp,seg.back()[1]-=pp;
break;
}
else{
cout<<"-1\n";
return;
}
}
else{
if(seg[seg.size()-2][1]==0){
cout<<"-1\n";
return;
}
if(b[R]<seg[seg.size()-2][1]+1){
int len=seg.back()[1]-seg.back()[0]+1;
seg.pop_back();
seg.back()[1]+=len;
pp-=x;
}
else{
cout<<"-1\n";
return;
}
}
}
}
vector<int> ans;
for(int i=1;i<seg.size();i++){
int sz=seg[i][1]-seg[i][0]+1;
for(int j=seg[i][0];j<=seg[i][1];j+=k)ans.push_back(j);
}
cout<<ans.size()<<"\n";
for(auto it:ans)cout<<it<<" ";
cout<<"\n";
}
signed main(){
cin.tie(0)->sync_with_stdio(0);
int T=1;
cin>>T;
while(T--)solve();
return 0;
}
题意:
只包含012的字符串,相邻的01可以抵消,可以将2变成0或1,询问最后的最短长度
思路:
#include
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N=3010;
const int INF=1e18;
// const int mod=998244353;
const int mod=1e9+7;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
void solve(){
string s;
cin>>s;
vector<int> odd(3),even(3);
for(int i=0;i<s.size();i++){
i%2==0?even[s[i]-'0']++:odd[s[i]-'0']++;
}
for(int i=0;i<2;i++){
int x=min(odd[i],even[i]);
odd[i]-=x;
even[i]-=x;
if(odd[i]){
int x=min(odd[i],even[2]);
odd[i]-=x;
even[2]-=x;
}
if(even[i]){
int x=min(even[i],odd[2]);
even[i]-=x;
odd[2]-=x;
}
}
int x=min(even[2],odd[2]);
even[2]-=x,odd[2]-=x;
int ans=0;
for(int i=0;i<3;i++)ans+=odd[i]+even[i];
cout<<ans<<"\n";
}
signed main(){
cin.tie(0)->sync_with_stdio(0);
int T=1;
cin>>T;
while(T--)solve();
return 0;
}
题意:
u
? a b
0
1
2
! u
输出答案思路:
? u v
,如果为0
则答案是u
否则v
? v0 v1
,如果为1
说明答案为重心u
,如果为0
则将u
打上标记把v0
以上的部分全部剪掉,然后递归v0
,否则递归v1
0
为2
的情况和两条边一样,唯独为1
时,此时剩余的树为u
加上v3
的子树大小,根据重心的性质:子树大小一定都小于等于一半,但是+1未必,v1 v2 v3
不能随便选,需要选择较大子树的两个点作为v1 v2
,保证最后一个子树v3
的点+1小于等于一半(这样的点总是存在),如果乱选的话在特殊数据会增加答案询问。返回1
则剪掉v1
和v2
#include
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N=3010;
const int INF=1e18;
// const int mod=998244353;
const int mod=1e9+7;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
int ask(int x,int y){
cout<<"? "<<x<<" "<<y<<endl;
cin>>x;
return x;
}
void claim(int x){
cout<<"! "<<x<<endl;
}
void solve(){
int n;
cin>>n;
vector<int> adj[n+1];
for(int i=1;i<=n;i++){
int x,y;
cin>>x>>y;
if(x!=0)adj[i].push_back(x),adj[x].push_back(i);
if(y!=0)adj[i].push_back(y),adj[y].push_back(i);
}
vector<int> st(n+1);
function<int(int,int)> get_size=[&](int u,int fa){
if(st[u])return 0ll;
int res=1;
for(auto v:adj[u]){
if(v==fa)continue;
res+=get_size(v,u);
}
return res;
};
function<int(int,int,int,int&)> get_wc=[&](int u,int fa,int tot,int &wc){
if(st[u])return 0ll;
int sum=1,ms=0;
for(auto v:adj[u]){
if(v==fa)continue;
int t=get_wc(v,u,tot,wc);
ms=max(ms,t);
sum+=t;
}
ms=max(ms,tot-sum);
if(ms<=tot/2)wc=u;
return sum;
};
bool g=0;
function<void(int)> cal=[&](int u){
if(st[u])return;
if(g)return;
get_wc(u,0,get_size(u,0),u);
vector<int> tmp;
for(auto v:adj[u]){
if(!st[v])tmp.push_back(v);
}
if(tmp.size()==0){
claim(u);
g=1;
return;
}
if(tmp.size()==1){
int x=ask(u,tmp[0]);
if(x==0){
claim(u);
g=1;
return;
}
else{
claim(tmp[0]);
g=1;
return;
}
}
if(tmp.size()==2){
int x=ask(tmp[0],tmp[1]);
if(x==1){
claim(u);
g=1;
return;
}
st[u]=1;
if(x==0){
cal(tmp[0]);
return;
}
cal(tmp[1]);
return;
}
int sz[3];
vector<array<int,2>> f;
for(int i=0;i<3;i++)f.push_back({tmp[i],get_size(tmp[i],u)});
sort(f.begin(),f.end(),[&](const array<int,2> &x,const array<int,2> &y){
return x[1]>y[1];
});
for(int i=0;i<3;i++)tmp[i]=f[i][0];
int x=ask(tmp[0],tmp[1]);
if(x==1){
st[tmp[0]]=st[tmp[1]]=1;
cal(u);
return;
}
else if(x==0){
st[u]=1;
cal(tmp[0]);
return;
}
else{
st[u]=1;
cal(tmp[1]);
return;
}
};
cal(1);
}
signed main(){
cin.tie(0)->sync_with_stdio(0);
int T=1;
cin>>T;
while(T--)solve();
return 0;
}
题意:
对于每个点,计算树的拓扑序的个数满足 p i = i p_i=i pi=i
思路:
#include
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N=5010,M=4e5+10;
const int INF=1e18;
const int mod=998244353;
// const int mod=1e9+7;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
int n,fac[N],invfac[N],siz[N],mul[N],f[N],dp[N][N];
vector<int> adj[N];
int qpow(int a,int b){
int ans=1;
for(;b;b>>=1){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
}
return ans;
}
void init(){
fac[0]=1;
for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
invfac[n]=qpow(fac[n],mod-2);
for(int i=n-1;i>=0;i--)invfac[i]=invfac[i+1]*(i+1)%mod;
}
int C(int n,int m){
if(n<m)return 0;
return fac[n]*invfac[m]%mod*invfac[n-m]%mod;
}
void dfs(int u){
siz[u]=f[u]=mul[u]=1;
for(auto v:adj[u]){
dfs(v);
siz[u]+=siz[v];
mul[u]=mul[u]*mul[v]%mod;
}
mul[u]=mul[u]*siz[u]%mod;
f[u]=fac[siz[u]]*qpow(mul[u],mod-2)%mod;
}
void dfs1(int u){
for(auto v:adj[u]){
int tmp=f[u]*mul[v]%mod*siz[u]%mod*qpow(siz[u]-siz[v],mod-2)%mod*invfac[siz[u]]%mod*fac[siz[u]-siz[v]]%mod;
// cout<
for(int i=1;i<=n;i++){
dp[v][i]=dp[u][i-1]*tmp%mod*C(n-i+1-siz[v],siz[u]-siz[v]-1)%mod;
dp[v][i]+=dp[v][i-1];
dp[v][i]%=mod;
}
dfs1(v);
}
}
void solve(){
cin>>n;
init();
for(int i=2;i<=n;i++){
int x;
cin>>x;
adj[x].push_back(i);
}
dp[1][1]=1;
dfs(1);
dfs1(1);
for(int i=1;i<=n;i++){
dp[i][i]=dp[i][i]*f[i]%mod*C(n-i,siz[i]-1)%mod;
cout<<dp[i][i]<<" \n"[i==n];
}
}
signed main(){
cin.tie(0)->sync_with_stdio(0);
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
题意:
给定一个长度为nm的整数序列,将其打乱之后按顺序填入
n ×m的网格中。定义bingo 整数为最小的整数k,满足存
在至少一行或者一列,其中所有的数都≤k。求出所有
(nm)! 种打乱方式的 bingo 整数之和,对 998244353 取模。
n m ≤ 200000 nm \leq 200000 nm≤200000
思路:
namespace NTT{
static constexpr int P=998244353;
int rev[N],bit=0,tot,g=3,gi;
int qpow(int a,int b){
int ans=1;
for(;b;b>>=1){
if(b&1)ans=ans*a%P;
a=a*a%P;
}
return ans;
}
int inv(int n){
return qpow(n,P-2);
}
void ntt(int a[],int inv){
for(int i=0;i<tot;i++){
if(i<rev[i])swap(a[i],a[rev[i]]);
}
for(int mid=1;mid<tot;mid<<=1){
int g1=qpow(inv==1?g:gi,(P-1)/(mid*2));
for(int i=0;i<tot;i+=mid*2){
int gk=1;
for(int j=0;j<mid;j++,gk=gk*g1%P){
auto x=a[i+j],y=gk*a[i+j+mid]%P;
a[i+j]=(x+y)%P,a[i+j+mid]=(x-y+P)%P;
}
}
}
if(inv==-1){
int tmp=NTT::inv(tot);
for(int i=0;i<tot;i++)a[i]=a[i]*tmp%P;
}
}
void init(int n){
bit=0;
while((1<<bit)<n)bit++;
tot=1<<bit;
for(int i=0;i<tot;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
gi=inv(g);
}
}
int f[N],g[N],fac[N],invfac[N];
void init(){
for(int i=(fac[0]=1);i<N;i++)fac[i]=fac[i-1]*i%mod;
invfac[N-1]=NTT::inv(fac[N-1]);
for(int i=N-2;i>=0;i--)invfac[i]=invfac[i+1]*(i+1)%mod;
}
int C(int n,int m){
if(n<m||m<0)return 0;
return fac[n]*invfac[m]%mod*invfac[n-m]%mod;
}
void solve(){
int n,m;
cin>>n>>m;
vector<int> a(n*m+1);
for(int i=1;i<=n*m;i++)cin>>a[i];
sort(a.begin(),a.end());
for(int i=0;i<=n*m;i++){
if(i==0)f[i]=0;
else f[i]=a[i]*fac[i-1]%mod;
}
for(int i=0;i<=n*m;i++)g[i]=invfac[n*m-i];
NTT::init(n*m*2+1);
for(int i=n*m+1;i<NTT::tot;i++)f[i]=g[i]=0;
NTT::ntt(f,1),NTT::ntt(g,1);
for(int i=0;i<NTT::tot;i++)f[i]=f[i]*g[i]%mod;
NTT::ntt(f,-1);
for(int i=0;i<=n*m;i++)g[i]=i*fac[n*m-i]%mod*f[n*m+i]%mod;
int ans=0;
for(int i=0;i<=n;i++){
for(int j=0;j<=m;j++){
int t=C(n,i)*C(m,j)%mod*g[m*i+n*j-i*j]%mod;
if((i+j)&1)ans=(ans+t)%mod;
else ans=(ans-t+mod)%mod;
}
}
cout<<ans<<"\n";
}