A.CCA的词典
没啥好讲的,map记录下出没出现过,然后每次查询枚举下可能的来源,叠加贡献即可。注意特判aa这种情况
map<string,int>cnt;
int main(){
int n;
cin>>n;
for(int i=0;i<n;++i){
string t;
cin>>t;
cnt[t]++;
}
int q;
read(q);
while(q--){
string s;
cin>>s;
int ans=cnt[s];
if(s.size()==2&&s[0]!=s[1]){
swap(s[0],s[1]);
ans+=cnt[s];
}
cout<<ans<<endl;
}
return 0;
}B.CCA的搬运
差点死在这题。。
想到了最优的顺序是按照要拿的顺序堆在一起,但是没注意到一个东西可以拿几次。。
按照第一次出现的顺序堆起来,之后模拟即可。
const int maxn=2e3+10;
struct node{
int val,id;
}st[maxn];
int top;
int w[maxn];
int vis[maxn];
int pi[maxn];
int n,m;
int main(){
//freopen("in.txt","r",stdin);
read(n),read(m);
for(int i=1;i<=n;++i)read(w[i]);
for(int i=1;i<=m;++i){
int x;
read(x);
pi[i]=x;
if(!vis[x]){
st[++top]={w[x],x};
}
vis[x]=1;
}
int ans=0;
for(int i=1;i<=m;++i){
for(int j=1;j<=top;++j){
if(st[j].id==pi[i]){
node tmp=st[j];
for(int k=j;k>=2;--k){
st[k]=st[k-1];
}
st[1]=tmp;
break;
}
else{
ans+=st[j].val;
}
}
}
cout<<ans<<endl;
return 0;
}C.CCA的子树
还是比较好想的树形dp。
题目要求选择的两个子树根节点不能有祖孙关系,其实也就是说,他们得是一个节点下,任意两个儿子所在子树的子树(有点绕),也就是说,他们的lca不能是他们其中的一个。若分别取枚举两个子树的根节点则需要的时间,所以考虑在他们的lca处合并。对于一个lca,我们向下找要求的子树即可(qaq真的不知道怎么表达)。具体看代码:
#define int ll
const int maxn=2e5+10;
struct Edge{
int to,next;
}e[maxn<<1];
int head[maxn],cnt;
void add(int x,int y){
e[cnt].to=y;
e[cnt].next=head[x];
head[x]=cnt++;
}
int w[maxn];
int sum_of_son[maxn];
int mx_of_son[maxn];
int n;
void dfs(int u,int fa){
sum_of_son[u]=w[u];
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(v==fa)continue;
dfs(v,u);
sum_of_son[u]+=sum_of_son[v];
}
}
int ans=-inf;
void solve(int u,int fa){
vector<int>tmp;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(v==fa)continue;
solve(v,u);
tmp.push_back(mx_of_son[v]);
}
sort(tmp.begin(),tmp.end(),greater<int>());
mx_of_son[u]=sum_of_son[u];
if(tmp.size()<1)return ;
mx_of_son[u]=max(mx_of_son[u],tmp[0]);
if(tmp.size()<2)return ;
ans=max(ans,tmp[0]+tmp[1]);
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
//clock_t c1 = clock();
//===========================================================
read(n);
memset(mx_of_son,-inf,sizeof(mx_of_son));
memset(head,-1,sizeof(head));
rep(i,1,n)read(w[i]);
rep(i,2,n){
int u,v;
read(u),read(v);
add(u,v);add(v,u);
}
dfs(1,-1);
solve(1,-1);
//cout<<endl;
if(ans==-inf){
puts("Error");
}
else{
cout<<ans<<endl;
}
//===========================================================
//std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
return 0;
}
D.CCA的小球
这题本质解法是容斥原理。但个人感觉细节还是蛮多的Orz。
首先,正面算的话想不出来,所以考虑下容斥。
那么,正难则反,考虑n个球任意排列,方案数为n!.
题目要求不能有相邻球颜色相同,所以,我们需要减去不合理方案。根据容斥公式:
设至少有i组相邻颜色相同小球的方案数为f(i)
则,答案为
考虑:假设现在要求至少i组相邻小球颜色相同,则,考虑捆绑法,将这i组小球分别捆绑,则,原来n个小球就变成了n-i个小球全排列。同时,考虑我们上面的总情况没有去除两个相同颜色小球颠倒位置的情况,所以需要乘上
,综上
最后,我们还是要去掉两个颜色相同小球颠倒的情况,所以,乘个的逆元即可。
另外,对于上面的式子,我们也可以用二项式反演处理:
设g(i)为恰好有i组相邻小球颜色相同,则:
(为什么要乘上组合数:每次可以选择不同颜色相邻)
根据反演公式:
以此代替容斥原理(不过感觉难点不在这吧,而是在如何求出)
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(int i = a; i <= n; ++ i)
#define per(i, a, n) for(int i = n; i >= a; -- i)
//#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
{
write(x/10);
}
putchar(x%10+'0');
}
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){
ll ans=1;
while(n){
if(n&1) ans=(ans*a)%mod;
a=a*a%mod;
n>>=1;
}
return ans%mod;
}
//==============================================================
const int maxn=1e6+10;
#define int ll
int n;
int a[maxn];
int f[maxn];
int pow2[maxn];
int finv[maxn];
int inv2[maxn];
unordered_map<int,int>cnt;
void init(){
f[0]=1;
rep(i,1,maxn-1)f[i]=f[i-1]*i%mod;
finv[maxn-1]=ksm(f[maxn-1],mod-2);
for(int i=maxn-2;i>=0;--i){
finv[i]=1ll*finv[i+1]*(i+1)%mod;
}
pow2[0]=1;
for(int i=1;i<maxn;++i){
pow2[i]=1ll*pow2[i-1]*2%mod;
}
inv2[0]=1;
ll inv22=ksm(2,mod-2);
for(int i=1;i<maxn;++i){
inv2[i]=inv2[i-1]*inv22%mod;
}
}
ll C(ll n,ll m){
if(m>n||m<0)return 0;
//cerr<<n<<" "<<m<<endl;
//cerr<<f[n]<<" "<<finv[n-m]<<" "<<finv[m]<<endl;
return 1ll*f[n]*finv[n-m]%mod*finv[m]%mod;
}
int sig(int x){
return (x&1)?-1:1;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
//clock_t c1 = clock();
//===========================================================
init();
read(n);
ll res=f[n];
for(int i=1;i<=n;++i){
read(a[i]);
cnt[a[i]]++;
}
int cnt2=0;
for(auto x:cnt)cnt2+=(x.second==2);
for(int i=1;i<=cnt2;++i){
res=(res+sig(i)*C(cnt2,i)*f[n-i]%mod*pow2[i]%mod)%mod;
res=(res%mod+mod)%mod;
}
cout<<res*inv2[cnt2]%mod<<endl;
//===========================================================
//std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
return 0;
}
京公网安备 11010502036488号