A
推了推发现成了原题,直接度了一发随便改改就过了
原题参考 https://blog.csdn.net/MIECZ/article/details/80591212
#define IN_LB() freopen("C:\\Users\\acm2018\\Desktop\\in.txt","r",stdin)
#define OUT_LB() freopen("C:\\Users\\acm2018\\Desktop\\out.txt","w",stdout)
#define IN_PC() freopen("C:\\Users\\hz\\Desktop\\in.txt","r",stdin)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200005;
ll fac[maxn],MOD = 1e9+7;
void init() {
int i;
fac[0] =1;
for(i =1; i <= (int)2e5+10; i++) //modify
fac[i] = fac[i-1]*i % MOD;
}
ll fastpow(ll a, ll b) {
ll tmp = a % MOD, ans =1;
while(b) {
if(b &1)
ans = ans * tmp % MOD;
tmp = tmp*tmp % MOD;
b >>=1;
}
return ans;
}
ll comb(ll n, ll m) {
return m>n ? 0 : fac[n]*fastpow(fac[m]*fac[n-m], MOD-2) % MOD;
}
ll Lucas(ll n, ll m) {
return m ? (comb(n%MOD, m%MOD)*Lucas(n/MOD, m/MOD))%MOD : 1;
}
int main() {
// IN_LB();
init();
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
n+=2,m+=2;
cout<<(Lucas(n+m-4,n-2)*Lucas(n+m-4,n-2)%MOD-Lucas(n+m-4,n-1)*Lucas(n+m-4,m-1)%MOD+MOD)%MOD<<endl;
}
return 0;
}
B
oeis了之后找到了递推式
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll k,mod;
while(cin>>k>>mod){
ll n=0,a=1,b=0,c=1;
for(int i=1;i<=k;i++){
ll tmp=n*(b+c)-n*(n-1)/2*a;
tmp%=mod;
if(tmp<0)tmp+=mod;
a=b,b=c;
c=tmp;
n++;
}
cout<<c<<endl;
}
}
D
n!
n
!
暴力枚举同构,除以自同构
#include <bits/stdc++.h>
using namespace std;
int n,na,nb,m,ans,tota,totb,id[10],u[1007],v[1007],ta[10],tb[10];
bool f[10][10],g[10][10],vis[10];
inline bool pd (){
// for (int i=1;i<=tota;i++)cout<<i<<' '<<ta[i]<<endl;
for (int i=1;i<=tota;i++){
for (int j=i;j<=tota;j++){
if (f[i][j]!=f[ta[i]][ta[j]])return false;
}
}
// cout<<1<<endl;
return true;
}
void pre (int tmp){
if (tmp>tota){
if (pd ())m++;
return ;
}
for (int i=1;i<=tota;i++){
if (!vis[i]){
vis[i]=1;
ta[tmp]=i;
pre(tmp+1);
vis[i]=0;
}
}
}
inline bool pd2 (){
for (int i=1;i<=tota;i++){
for (int j=i;j<=tota;j++){
if (f[i][j]&&!g[tb[i]][tb[j]])return false;
}
}
return true;
}
void work (int tmp){
if (tmp>tota){
if (pd2 ())ans++;
return ;
}
for (int i=1;i<=totb;i++){
if (!vis[i]){
vis[i]=1;
tb[tmp]=i;
work(tmp+1);
vis[i]=0;
}
}
}
void init (){
memset (f,0,sizeof (f));
memset (g,0,sizeof (g));
memset (vis,0,sizeof (vis));
m=ans=tota=totb=0;
for (int i=1;i<=na;i++){
scanf ("%d%d",&u[i],&v[i]);
vis[u[i]]=1;
vis[v[i]]=1;
}
for (int i=1;i<=n;i++){
if (vis[i]){
id[i]=++tota;
}
}
for (int i=1;i<=na;i++){
f[id[u[i]]][id[v[i]]]=1;
f[id[v[i]]][id[u[i]]]=1;
// cout<<id[u[i]]<<' '<<id[v[i]]<<endl;
}
memset (vis,0,sizeof (vis));
pre (1);
memset (vis,0,sizeof (vis));
for (int i=1;i<=nb;i++){
scanf ("%d%d",&u[i],&v[i]);
vis[u[i]]=1;
vis[v[i]]=1;
}
for (int i=1;i<=n;i++){
if (vis[i]){
id[i]=++totb;
}
}
for (int i=1;i<=nb;i++){
g[id[u[i]]][id[v[i]]]=1;
g[id[v[i]]][id[u[i]]]=1;
// cout<<id[u[i]]<<' '<<id[v[i]]<<endl;
}
memset (vis,0,sizeof (vis));
work (1);
}
int main (){
while (~scanf ("%d%d%d",&n,&na,&nb)){
init ();
// cout<<ans<<' '<<m<<endl;
ans/=m;
printf("%d\n",ans);
}
return 0;
}
E
参考这个题dp部分的去重思路就行了 http://acm.hdu.edu.cn/showproblem.php?pid=6155
#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,m,K,f[100007][15][15],a[100007];
void work (){
int i,j,k;
for (i=1;i<=n;i++){
for (k=1;k<=m;k++){
if (i==k)
f[i][0][k]=1;
else f[i][0][k]=0;
// cout<<i<<' '<<0<<' '<<k<<f[i][0][k]<<endl;
}
for (j=1;j<=K;j++){
if (a[i]==j)f[i][j][0]=1;
else f[i][j][0]=0;
// cout<<i<<' '<<j<<' '<<0<<' '<<f[i][j][0]<<endl;
for (k=1;k<=min(m,i-1);k++){
f[i][j][k]=0;
if (a[i]==j){
int sum=0;
for (int p=0;p<=K;p++){
sum=(sum+f[i-1][p][k])%mod;;
}
f[i][j][k]=(f[i][j][k]+sum)%mod;
}
else {
f[i][j][k]=f[i-1][j][k-1];
}
// cout<<i<<' '<<j<<' '<<k<<' '<<f[i][j][k]<<endl;
}
for (;k<=m;k++){
f[i][j][k]=0;
}
}
}
int ans=0;
for (int i=1;i<=K;i++){
ans=(ans+f[n][i][m])%mod;
}
printf("%d\n",ans);
}
int main(){
while (~scanf ("%d%d%d",&n,&m,&K)){
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
work ();
}
return 0;
}
F
贴了个求
∑ni=1ik
∑
i
=
1
n
i
k
的板子,排序之后,枚举最大值取到相邻两个上界之间的区间上的贡献,求个和就行了。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=2005,mo=1e9+7;
typedef long long LL;
int T,k,b[maxn],c[maxn][maxn],Inv[maxn],ans,tmp;
LL calc(LL n,int k){
n++; n%=mo; tmp=n;
ans=0;
for (int i=1;i<=k+1;i++)
{
ans=(ans+(LL)c[k+1][i]*b[k+1-i]%mo*n%mo) % mo;
n=(LL)n*tmp % mo;
}
ans=(LL)ans*Inv[k+1] % mo;
return ans;
}
LL a[1003];
LL n;
LL pow(LL n,LL p){
LL ans=1;
LL base=n;
while(p){
if(p&1){
ans=ans*base%mo;
}
base=base*base%mo;
p>>=1;
}
return ans;
}
int main()
{
c[0][0]=1;
for (int i=1;i<maxn;i++)
{
for (int j=1;j<=i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j]) % mo;
c[i][0]=1;
}
Inv[1]=1;
for (int i=2;i<maxn;i++) Inv[i]=(LL)Inv[mo % i] * (mo-mo/i) % mo;
b[0]=1;
for (int i=1;i<maxn;i++)
{
b[i]=0;
for (int k=0;k<i;k++) b[i]=(b[i]+(LL)c[i+1][k]*b[k] % mo) % mo;
b[i]=((LL)b[i]*(-Inv[i+1]) % mo+mo)%mo;
}
while(~scanf("%lld",&n)){
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
sort(a+1,a+1+n);
LL mul=1;
LL sum=0;
for(int i=1;i<=n;i++){
if(a[i]==a[i-1]){
mul=mul*a[i]%mo;
continue;
}
LL k=n-i+1;
LL tmp=pow(a[i],k+1)-pow(a[i-1],k)*(a[i-1]+1);
tmp%=mo;
if(tmp<0)tmp+=mo;
LL p1=calc(a[i]-1,k)-calc(a[i-1],k);
tmp-=p1;
tmp%=mo;
if(tmp<0)tmp+=mo;
sum=(sum+tmp*mul)%mo;
mul=mul*a[i]%mo;
}
printf("%lld\n",sum);
}
}
I
3!
3
!
枚举映射,倍长,用SA统计不同字串的个数,除以6去重,只含有单个字符的除以3
//SA
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=305000;
typedef long long ll;
int s[maxn];
int sa[maxn], t[maxn], t2[maxn], c[maxn], n;
int Rank[maxn], height[maxn];
void build_sa(int m, int n){
int i, *x=t, *y=t2;
for(i=0;i<m;i++)c[i]=0;
for(i=0;i<n;i++)c[x[i]=s[i]]++;
for(i=1;i<m;i++)c[i]+=c[i-1];
for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
for(int k=1;k<=n;k<<=1){
int p=0;
for(i=n-k;i<n;i++)y[p++]=i;
for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
for(i=0;i<m;i++)c[i]=0;
for(i=0;i<n;i++)c[x[y[i]]]++;
for(i=1;i<m;i++)c[i]+=c[i-1];
for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
swap(x, y);
p=1;x[sa[0]]=0;
for(i=1;i<n;i++)
x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
if(p>=n)break;
m=p;
}
}
void geth(int n){
int i, j, k=0;
for(i=0;i<n;i++)Rank[sa[i]]=i;
for(i=0;i<n;i++){
if(k)k--;
if(Rank[i]==0)break;
j=sa[Rank[i]-1];
while(s[i+k]==s[j+k])k++;
height[Rank[i]]=k;
}
}
int tot;
char str[50003];
void add(int a,int b,int c){
for(int i=0;i<n;i++){
if(str[i]=='a'){
s[tot++]=a;
}
else if(str[i]=='b'){
s[tot++]=b;
}
else {
s[tot++]=c;
}
}
}
int main()
{
/*n=8;
s[8]=0;
s[0]=s[1]=2;
s[2]=s[3]=s[4]=s[5]=1;
s[6]=s[7]=3;
build_sa(200, n+1);
geth(n+1);
for(int i=0;i<=n;i++){
printf("%d ", sa[i]);
}
printf("\n");
for(int i=1;i<=n;i++){
printf("%d ", height[i]);
}
printf("\n");*/
while(~scanf("%d%s",&n,str)){
tot=0;
add(1,2,3);
s[tot++]=0;
add(1,3,2);
s[tot++]=0;
add(2,1,3);
s[tot++]=0;
add(2,3,1);
s[tot++]=0;
add(3,1,2);
s[tot++]=0;
add(3,2,1);
s[tot++]=0;
build_sa(10,tot);
geth(tot);
ll sum=0;
int last=0;
for(int i=6;i<tot;i++){
int tmp=n-sa[i]%(n+1);
int tadd=tmp-min(height[i],min(last,tmp));
sum+=tadd;
last=tmp;
}
ll sig=0;
ll len=0;
for(int i=0;i<n;i++){
if(i>0&&str[i]!=str[i-1]){
sig=max(sig,len);
len=1;
}
else len++;
}
sig=max(sig,len);
//cout<<sum<<' '<<sig<<endl;
printf("%lld\n",(sum+sig*3)/6);
}
}
J
莫队加上奇偶排序的常数优化就卡过去了
#include <bits/stdc++.h>
using namespace std;
int a[100003];
int n,q;
struct que{
int l,r,id;
}rec[100003];
int bsize;
bool cmp(que a,que b){
if(a.l/bsize==b.l/bsize){
if((a.l/bsize)%2)return a.r<b.r;
else return a.r>b.r;
}
return a.l/bsize<b.l/bsize;
}
int c[100003];
int tmp,tl,tr;
int ans[100003];
inline void update(int x,int add){
if(add==1){
if(c[x]==0)tmp++;
c[x]++;
}
else {
if(c[x]==1)tmp--;
c[x]--;
}
}
int main(){
while(~scanf("%d%d",&n,&q)){
bsize=sqrt(q);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=q;i++){
scanf("%d%d",&rec[i].l,&rec[i].r);
rec[i].id=i;
}
memset(c,0,sizeof(c));
tmp=0;
tl=0,tr=n+1;
sort(rec+1,rec+1+q,cmp);
for(int i=1;i<=q;i++){
while(tl<rec[i].l){
update(a[++tl],1);
}
while(tr>rec[i].r){
update(a[--tr],1);
}
while(tl>rec[i].l){
update(a[tl--],-1);
}
while(tr<rec[i].r){
update(a[tr++],-1);
}
ans[rec[i].id]=tmp;
}
for(int i=1;i<=q;i++)printf("%d\n",ans[i]);
}
}