A:
长度最小就是每k个小写字母形成一组,这样能保证最短的拥有全部子序列
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,M=2*N,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;const long long inf=1e18;int n,m,k;void solve()
{cin>>n>>m;for(int i=1;i<=n;i++){for(int j=0;j<m;j++){cout<<(char)(j+'a');}}cout<<"\n";
} signed main()
{cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);int t=1;cin>>t;while(t--) solve();
}
B:
让gcd最大就是让 n个数都是这个gcd的倍数
假设 x%n==0才能通过n个数分配完x
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,M=2*N,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;const long long inf=1e18;int n,m,k;void solve()
{cin>>n>>m;vector<int> a;for(int i=1;i<=n/i;i++){if(n%i==0){a.push_back(i);if(i*i!=n){a.push_back(n/i);}}}int res=0;for(auto x:a){if(n/x>=m) res=max(res,x);}cout<<res<<"\n";
} signed main()
{cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);int t=1;cin>>t;while(t--) solve();
}
C:
脑子短路的一题...
考虑如何构造最短的字符串满足有n长度的所有k个字母的子序列
没错!那就是A的结论,要有n组完整的包括k个字母否则就会缺失
考虑正常思考
假设第一字母 后面如果要包含n长度的k个子序列 那么 后面至少有n-1组都有k个字母的序列
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,M=2*N,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;const long long inf=1e18;int n,m,k;void solve()
{map<char,int> mp;cin>>n>>k>>m;string s;cin>>s;s="?"+s;int i=1;int cnt=0;string res="";while(i<=m&&cnt<n){mp.clear();int j=i;int sum=0;while(j<=m&&sum<k){int c=s[j]-'a';if(c<k&&mp[c]==0) sum++;mp[c]++;j++;}if(sum<k) break;cnt++;res+=s[j-1];i=j;}if(cnt==n) cout<<"YES\n";else{cout<<"NO\n";for(int i=0;i<k;i++){if(mp[i]==0){cout<<res<<string(n-res.size(),char('a'+i))<<"\n";return ;}}cout << res << string(n - res.size(), 'a') << '\n';}
} signed main()
{cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);int t=1;cin>>t;while(t--) solve();
}
D:
考虑每个朋友对的贡献
当前 x朋友和y朋友的友谊是 z
那么根据期望定义选中的次数可以是0 1 2 3 4... k
那么假设当前选中的次数是 j
P=n*(n-1)/2 即从n个人里面选出来 一对朋友 就会有P种不同情况
那么选一次的情况下,同时选x朋友和y朋友的概率就是 1/P
不能同时选出来就是 (P-1)/P
那么概率就是 (z*j+(j-1)*j)/2) *C(k,j)* (1/P)^(j) * ((P-1)/P)^(k-j)
就是 第一个式子就是贡献嘛 j*z 加上 1+2+...+j-1 等差数列
然后后面就是k轮里面跳j轮
然可以发现右边式子都相同,合并Z就好了
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,M=2*N,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;const long long inf=1e18;int n,m,k;
int fact[N],infact[N];int qmi(int a,int k,int p){int res=1;while(k){if(k&1) res=(LL) res*a%p;a=(LL)a*a%p;k>>=1;}return res;
}
void init(){fact[0]=infact[0]=1;for(int i=1;i<N;i++){fact[i]=(LL)fact[i-1]*i%mod;infact[i]=(LL)infact[i-1]*qmi(i,mod-2,mod)%mod;}
}
int C(int a,int b){if(b<0||b>a) return 0;return ((LL)fact[a] * infact[b] % mod * infact[a - b] % mod);
}
int inv(int x){return qmi(x,mod-2,mod);
}
int a[N];
void solve()
{cin>>n>>m>>k;int sum=0,tot=n*(n-1)/2%mod;for(int i=1;i<=m;i++){int x,z,y;cin>>x>>y>>z;sum+=z;}int res=0;tot%=mod;for(int j=1;j<=k;j++){res+=C(k,j)*((__int128)j*sum%mod+j*(j-1)%mod*inv(2)%mod*m%mod)%mod*qmi(inv(tot),j,mod)%mod*qmi(tot-1,k-j,mod)%mod*qmi(inv(tot),k-j,mod);res%=mod;}cout<<res<<"\n";//C(k,j)*(1/sum)^j
} signed main()
{cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);int t=1;init();cin>>t;while(t--) solve();
}
E:
最多n个码头
先想两个码头之间的贡献咋计算
2 6
假设2 和6是码头
那么我们要计算中间的答案就是
v[2]*(6-3) + v[2]*(6-4) +v[2]*(6-5)
=v[2]*(1+2+3)=v[2]*(3*(3+1)/2) 就是等差数列后一项
所以线段树直接维护这个就好了
比如第二个点维护 2到6中间的贡献
然后修改操作
我们需要插入给4
那么我们直接在4这里面插入4到6的船的贡献
找4前面的点2,把点2修改成2到4的点
所以我们需要一个set二分logn查找前一个已经存在的码头
查询操作
1 [ 4 8 ] 10
上面有的数字都是码头,没有的化就是船
然后思考咋计算贡献
答案就是 4+8的点的贡献+ v[1]*(4-l) - v[8]*10-r即可
#include<bits/stdc++.h>
using namespace std;
const int N =3e5+10,M=2*N,mod=1e9+7;typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;const long long inf=1e18;int n,m,k;
PII a[N];
LL sum[N*4];
int now[N];
void pushup(int u){sum[u]=sum[u<<1]+sum[u<<1|1];
}
void modify(int u,int l,int r,int c,int x,int y){if(l==r){sum[u]=1ll*x*y*(y-1)/2;return ;}int mid=l+r>>1;if(c<=mid) modify(u<<1,l,mid,c,x,y);else modify(u<<1|1,mid+1,r,c,x,y);pushup(u);
}
LL query(int u,int l,int r,int L,int R){if(L>R) return 0;if(l>=L&&r<=R) return sum[u];int mid=l+r>>1;LL res=0;if(L<=mid) res+=query(u<<1,l,mid,L,R);if(R>mid) res+=query(u<<1|1,mid+1,r,L,R);return res;
}
void solve()
{int q;set<int> st;st.insert(0);cin>>n>>m>>q;for(int i=1;i<=m;i++) cin>>a[i].first;for(int i=1;i<=m;i++){cin>>a[i].second;now[a[i].first]=a[i].second;}sort(a+1,a+1+m);for(int i=1;i<m;i++){modify(1,1,n,a[i].first,a[i].second,a[i+1].first-a[i].first);}for(int i=1;i<=m;i++)st.insert(a[i].first);while(q--){int op,l,r;cin>>op>>l>>r;if(op==1){auto it=st.lower_bound(l);modify(1,1,n,l,r,*it-l);it--;modify(1,1,n,*it,now[*it],l-*it);now[l]=r;st.insert(l);}else{auto it1=st.lower_bound(l);auto it2=st.lower_bound(r);LL res=0;int L=*it1;int len1=L-l+1;int R=*it2;int len2=R-r;//中间的部分res+=query(1,1,n,*it1,*prev(it2));//加去左边多的部分it1--;res+=1ll*now[*it1]*len1*(len1-1)/2;//减去右边多的部分it2--;res-=1ll*now[*it2]*len2*(len2-1)/2;cout<<res<<"\n";}}
} signed main()
{cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);int t=1;//init();//cin>>t;while(t--) solve();
}