1005 Everything Is Generated In Equal Probability (数学)
http://acm.hdu.edu.cn/showproblem.php?pid=6595
题意
期望
给你一个N 问在1-N随机选择一个数,随机排列1-n 求逆序对,然后随机选择子序列 在求逆序对,直到数列长度为0 问逆序对的期望个数
思路
n个数全排列的逆序对期望个数为 (n*(n-1))/4 一共有n*(n-1)/2 是逆序对的期望为1/2
dp[i]为数组长度为i的后继期望
dp[i] = (n*(n-1))/4 + dp[i]*C[0][n]/pow(2,n) + ∑dp[i]*C[i][n]/pow(2,n)
dp[i] = (n(n-1)/4 + ∑dp[i]*C[i][n]/pow(2,n)) * pow(2,n) / (pow(2,n)-1;
对于N 计算dp 1-n的和 除以N
代码
#include
using namespace std;
typedef long long ll;
const ll mod = 998244353;
ll C[3300][3300];
ll dp[3300];
ll q[3300];
ll qw[3300];
ll qw2[3300];
ll qsort(ll x,ll n)
{
ll ans = 1;
while(n)
{
if(n % 2 == 1)
{
ans = (ans * x) % mod;
}
x = (x * x) % mod;
n /= 2;
}
ans %= mod;
return ans;
}
void ok()
{
ll xx = 1;
for(ll i = 1;i <= 3000;i++)
{
xx *= 2;
xx %= mod;
q[i] = xx;
qw[i] = qsort(xx,mod-2);
qw2[i] = qsort(xx-1,mod-2);
}
dp[0] = 0;
dp[1] = 0;
ll qwe = qsort(4,mod-2);
for(ll i = 2;i <= 3000;i++)
{
dp[i] = (i*(i-1)*qwe)%mod;
for(ll j = 1;j < i;j++)
{
dp[i] = (dp[i] + ((C[i][j]*dp[j])%mod)*qw[i])%mod;
}
dp[i] = ((dp[i]*q[i])%mod*(qw2[i]))%mod;
}
}
void cc(ll n)
{
for(ll i=0;i<=n;i++)
C[i][0]=1;
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=i;j++)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
int main()
{
ll n;
cc(3002);
ok();
while(scanf("%lld",&n)!= EOF)
{
ll ans = 0;
for(ll i = 2;i <= n;i++)
{
ans = (ans + dp[i]) % mod;
}
ans = (ans * qsort(n,mod-2))%mod;
printf("%lld\n",ans);
}
return 0;
}
1009 I Love Palindrome String (回文树)
http://acm.hdu.edu.cn/showproblem.php?pid=6599
题意
回文树
给你一个长度为n的字符串
为本身是回文串 前一半也是回文串的子串个数
思路
前一半是回文串 那么后一半也一定是回文串
回文树的fail指向以当前结尾的最长回文串,如何一个回文串的fail指针指向的回文串长度或继续向前 长度存在他的一半 那么他就是符合要求的回文串
递归找长度一半会超时 可以按fail指针方向边建一个树 跑DFS
代码
#include
using namespace std;
const int MAXN = 310005 ;
const int N = 26 ;
struct Palindromic_Tree {
int next[MAXN][N] ;//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成
int fail[MAXN] ;//fail指针,失配后跳转到fail指针指向的节点
long long cnt[MAXN] ;
//cnt[i]表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的)
int num[MAXN] ; //num[i]表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数
int len[MAXN] ;//len[i]表示节点i表示的回文串的长度
int S[MAXN] ;//存放添加的字符
int last ;//指向上一个字符所在的节点,方便下一次add
int n ;//字符数组指针
int p ;//节点指针
vector to[MAXN]; //失配指针反向边
int newnode ( int l ) {//新建节点
for ( int i = 0 ; i < N ; ++ i ) next[p][i] = 0 ;
cnt[p] = 0 ;
num[p] = 0 ;
len[p] = l ;
return p ++ ;
}
void init () {//初始化
p = 0 ;
newnode (0) ;
newnode (-1) ;
last = 0 ;
n = 0 ;
S[n] = -1 ;//开头放一个字符集中没有的字符,减少特判
fail[0] = 1 ;
to[1].push_back(0);
}
int get_fail ( int x ) {//和KMP一样,失配后找一个尽量最长的
while ( S[n - len[x] - 1] != S[n] ) x = fail[x] ;
return x ;
}
void add ( int c ) {
c -= 'a';
S[++ n] = c ;
// cout<= 0 ; -- i ) cnt[fail[i]] += cnt[i] ;
//父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!
}
} ;
Palindromic_Tree A;
char s[MAXN];
int vis[MAXN],ans[MAXN];
void dfs(int u)
{
if(vis[(A.len[u]+1) / 2] == 1) ans[A.len[u]] += A.cnt[u];
if(A.len[u] >= 0) vis[A.len[u]] = 1;
for(int i = 0;i < A.to[u].size();i++)
{
int v = A.to[u][i];
dfs(v);
}
if(A.len[u] >= 0) vis[A.len[u]] = 0;
}
int main()
{
while(scanf("%s",s ) != EOF)
{
int n = strlen(s);
for(int i = 0;i <= n;i++)
{
A.to[i].clear();
}
memset(ans,0,sizeof(ans));
A.init();
for(int i =0;i < n;i++)
{
A.add(s[i]);
}
A.count();
dfs(1);
ans[1] = n;
for(int i = 1;i <= n;i++)
{
if(i!= 1) printf(" ");
printf("%d",ans[i]);
}
printf("\n");
}
}
1010 Just Skip The Problem (思维)
http://acm.hdu.edu.cn/showproblem.php?pid=6600
题意
给你一个数n 你可以进行若干次询问 每次询问你给出一个数m 他会告诉你n^m 是否等于m
问最优解的情况下 询问的方案数
思路
最优解就是依次询问每一位 方案数为n!膜数是1e6+3 那么大于1e6+3的树为0
代码
#include
#define ll long long
#define mod 1000003
#define inf 0x3f3f3f3f
using namespace std;
int main()
{
ll n;
while(~scanf("%lld",&n))
{
ll ans=1;
if(n>=mod)
{
printf("0\n");
continue;
}
for(ll i=1; i<=n; i++)
ans=(ans*i)%mod;
printf("%lld\n",ans);
}
return 0;
}
1011 Keen On Everything But Triangle (主席树)
http://acm.hdu.edu.cn/showproblem.php?pid=6601
题意
给你n个数 m次询问 每次问区间l-r之间能组成最大三角形面积
思路
最不成三角形最优情况即斐波那契数列,可知区间长度大于40 一定有解
问题即求区间第k大 sort肯定超时 可以用主席树
代码
#include
#include
#define ll long long
#include
#include
using namespace std;
const ll MAX = 112345;
struct Node
{
ll sum, l, r;
} tree[MAX * 40];
ll root[MAX], cnt;
ll data[MAX];
vector sorted;
//离散化获得ID
ll get_id(ll x)
{
return lower_bound(sorted.begin(), sorted.end(), x) - sorted.begin() + 1;
}
void init()
{
cnt = 0;
root[0] = 0;
}
//根据旧版本的线段树创建新线段树的节点
ll create_node(ll po)
{
ll idx = ++cnt;
tree[idx].sum = tree[po].sum + 1;
tree[idx].l = tree[po].l;
tree[idx].r = tree[po].r;
return idx;
}
void updata(ll &o, ll po, ll l, ll r, ll pos)
{
o = create_node(po);
if (l == r) return;
ll m = (l + r) >> 1;
if (pos <= m) updata(tree[o].l, tree[po].l, l, m, pos);
else updata(tree[o].r, tree[po].r, m + 1, r, pos);
}
//二分查询
ll query(ll s, ll e, ll l, ll r, ll k)
{
if (l == r) return l;
ll m = (l + r) >> 1;
ll sum = tree[tree[e].l].sum - tree[tree[s].l].sum;
if (k <= sum) return query(tree[s].l, tree[e].l, l, m, k);
else return query(tree[s].r, tree[e].r, m + 1, r, k - sum);
}
int main()
{
ll n, m;
while (~scanf("%lld %lld", &n, &m))
{
init();
for (ll i = 1; i <= n; i++)
{
scanf("%lld", &data[i]);
sorted.push_back(data[i]);
}
sort(sorted.begin(), sorted.end());
sorted.erase(unique(sorted.begin(), sorted.end()), sorted.end());
ll num = sorted.size();
for (ll i = 1; i <= n; i++)
updata(root[i], root[i - 1], 1, num, get_id(data[i]));
for(ll i=0; ic)
{
ans=a+b+c;
break;
}
}
printf("%lld\n",ans);
}
}
return 0;
}
1012 Longest Subarray (线段树)
http://acm.hdu.edu.cn/showproblem.php?pid=6602
题意
给你c k 和n个数 求满足条件的最长区间长度
条件 每个数的个数>= k或者为0
思路
枚举每个右端点 求每个左端点1-c中满足条件的个数是多少 找最左端为c的点
代码
#include
using namespace std;
const int MAXN = 100005;
struct node
{
int data,lazy;
}tree[MAXN*4];
int a[MAXN];
int n,c,k;
vector q[MAXN];
int maxn,qw;
void build(int x,int l,int r)
{
tree[x].data = 0;
tree[x].lazy = 0;
if(l==r) return ;
int mid = (l + r) / 2;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
}
void pushdown(int rt)
{
if(tree[rt].lazy)
{
tree[rt*2].lazy += tree[rt].lazy;
tree[rt*2+1].lazy += tree[rt].lazy;
tree[rt*2].data += tree[rt].lazy;
tree[rt*2+1].data += tree[rt].lazy;
tree[rt].lazy = 0;
}
}
void updata(int l,int r,int rt,int L,int R,int x)
{
if(l > r) return ;
if(l == L&&r == R)
{
tree[rt].data += x;
tree[rt].lazy += x;
return ;
}
pushdown(rt);
int mid = (L + R) / 2;
if(mid >= r)
{
updata(l,r,rt*2,L,mid,x);
tree[rt].data = max(tree[rt*2].data,tree[rt*2+1].data);
}
else if(mid < l)
{
updata(l,r,rt*2+1,mid+1,R,x);
tree[rt].data = max(tree[rt*2].data,tree[rt*2+1].data);
}
else
{
updata(l,mid,rt*2,L,mid,x);
updata(mid+1,r,rt*2+1,mid+1,R,x);
tree[rt].data = max(tree[rt*2].data,tree[rt*2+1].data);
}
}
void query(int l,int r,int rt,int L,int R)
{
if(L==R)
{
if(tree[rt].data == c) qw = L;
return ;
}
pushdown(rt);
int mid = (L + R ) / 2;
if(mid >= r)
{
if(tree[rt*2].data >= c) query(l,mid,rt*2,L,mid);
}
else if(mid < l)
{
if(tree[rt*2+1].data >= c) query(l,mid,rt*2+1,mid+1,R);
}
else
{
if(tree[rt*2].data >= c) query(l,mid,rt*2,L,mid);
else if(tree[rt*2+1].data >= c) query(mid+1,r,rt*2+1,mid+1,R);
}
}
int main()
{
// freopen("in.txt","r",stdin);
while(scanf("%d%d%d",&n,&c,&k) != EOF)
{
for(int i = 1;i <= n;i++)
{
scanf("%d",&a[i]);
}
for(int i = 1;i <= c;i++)
{
q[i].clear();
q[i].push_back(0);
}
int ans=0;
build(1,1,n);
for(int i = 1;i <= n;i++)
{
int x = a[i];
q[x].push_back(i);
int siz = q[x].size();
if(siz > k)
{
int l = q[x][siz-k-1]+1,r = q[x][siz-k];
updata(l,r,1,1,n,1);
}
int l = q[x][siz-2]+1,r = i-1;
updata(l,r,1,1,n,-1);
updata(i,i,1,1,n,c-1);
qw = 0;
query(1,i,1,1,n);
if(qw != 0)
{
ans = max(i-qw+1,ans);
}
}
printf("%d\n",ans);
}
return 0;
}