Chef-jumping
没什么说的,对6取余,余数0,1,3就yes
数组初始最大值Max,最小值Min,
1)如果k==0
2)k%2 ==0 : a[i]-Min
3)k%2 ==1 : Max-a[i]
注意只要前缀。
对每一行单独考虑,如果修改的数不是在边上,左+右-后,那么他对答案的贡献是0,然后注意不能让i位置的数>i+1的
#include<stdio.h>
#include<string.h>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
vector<int>v[100005];
int n,m,p;
int x,y;
map<int,int>mp;
int main(){
scanf("%d%d%d",&n,&m,&p);
while(p--){
scanf("%d%d",&x,&y);v[x].push_back(y);
}
if(m==1){
for(int i=1;i<=n;i++) printf("0\n");
return 0;
}
for(int i=1;i<=n;i++){
int s=v[i].size(),tag=1,ans=m-1;
sort(v[i].begin(),v[i].end());
mp.clear();
for(int j=s-1;j>=0;j--){
if(v[i][j]==m) ans++;
else if(v[i][j]==1) ans--;
mp[v[i][j]]++;
int x=v[i][j]+1;
if(x<=m && x+mp[x]<mp[v[i][j]]+v[i][j]){
tag=0;break;
}
}
if(!tag) puts("-1");
else printf("%d\n",ans);
}
return 0;
}
vector<int>v[i]存第i种颜色的价格,s[i]=v[i].size();
假设总方案数是num,所有方案的花费和是w,结果就是w/num;
如何求num, sigma(cnt[i])(i>=m),如何求cnt[i]: sigma(1+((2^s[j])-1)*x)中选幂为i的。。展开就行了
如何求w,假如我要选i种颜色,并且颜色j必选,那么总的方案数就是way[j]=(sigma(1+((2^s[k])-1)*x)(k!=j)中选幂为i-1的),展开就行了,对于这所求的每一种方案,我们任意加入j颜色的数量都行,如果我们只买j颜色,那么总花费是:买了第k种j颜色,剩下的s[j]-1种j颜色的组合数是 2^(s[j]-1),所以花费是cost[k]=pri[k] * (2^(s[j]-1));也就是说只买j颜色的所有方案的花费和是avg[j] = sigma(cost[k]).
综上 sigma(avg[j] * way[j]) / sigma(cnt[i),i>=m);
#include<stdio.h>
#include<string.h>
#include<vector>
#include<stdlib.h>
#include<algorithm>
using namespace std;
inline int input(){
int ret=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0'&&c<='9'){
ret=ret*10+c-'0';
c=getchar();
}
return ret;
}
#define clr(a) memset(a,0,sizeof(a))
#define rep(i,s,t) for(int i=s;i<t;i++)
int t,n,m;
int x[50],y[50];
int to[50],cnt;
double avg[50];
double C[50][50];
double two[50];
double f[50],g[50];
vector<int>v[50];
inline void Init(){
rep(i,1,41) C[i][0]=C[i][i]=1,C[i][1]=i;
rep(i,2,41) rep(j,2,i) C[i][j]=C[i-1][j-1]+C[i-1][j];
two[0]=1;
rep(i,1,41) two[i]=two[i-1]*2;
}
int main(){
Init();
t=input();
while(t--){
n=input(),m=input();
cnt=0;clr(to);
rep(i,0,n){
x[i]=input(),y[i]=input();
if(to[x[i]]==0) to[x[i]]=(++cnt);
}
rep(i,1,cnt+1) v[i].clear();
rep(i,0,n) v[to[x[i]]].push_back(y[i]);
rep(i,1,cnt+1){
int s=v[i].size();
avg[i]=0;
rep(j,0,s){
avg[i]+=v[i][j]*two[s-1];
}
}
double ans=0;
rep(i,m,cnt+1){
rep(j,1,cnt+1){
clr(f),clr(g),f[0]=1;
rep(k,1,cnt+1){
if(k==j) continue;
int S=v[k].size();
rep(r,0,45){
g[r]+=f[r];
g[r+1]+=f[r]*(two[S]-1);
}
memcpy(f,g,sizeof(g)),clr(g);
}
ans+=avg[j]*f[i-1];
}
}
clr(f),clr(g),f[0]=1;
rep(i,1,cnt+1){
int S=v[i].size();
rep(j,0,45){
g[j]+=f[j];
g[j+1]+=f[j]*(two[S]-1);
}
memcpy(f,g,sizeof(g)),clr(g);
}
double num=0;
rep(i,m,cnt+1){
num+=f[i];
}
printf("%.8lf\n",ans/num);
}
return 0;
}
线段树:对于第一种和第二种操作要分别存一个值,因为((a^b)%p2) %p1!= ((a%p1)^b)%p2%p1;
操作1: (s+(i-x)*d)*r^(i-x) = ( (s-d*x)*r^i ) / (r^x) +( d*i*r^i ) / (r^x) ,如果知道了(r^x)对除数的逆元为ivr,那么也就是 (s-d*x)*ivr *r^i + d*ivr *i *r^i,很显然(s-d*x)*ivr和d*ivr都是定值,就变成简单的区间更新了。但前提是逆元存在,(a/r)%mod,r存在逆元,那么gcd(r.mod)==1,题里面这儿mod是素数,那如果r%mod==0,不能求逆元,那就更简单了,改变的只有一个点了
操作2,3:略过。
Ps: 因为p1,p2均为素数,所以可以用费马小定理(a^b%mod == (a^(b%(mod-1))) %mod) 减少运行时间。
#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <stdlib.h>
#include <string>
#include <math.h>
#include <map>
#include <algorithm>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
#define rep(i,s,t) for(int i=s;i<t;i++)
#define N 100005
#define L (t<<1)
#define R (t<<1|1)
typedef long long ll;
int t,n,q,r,p1,p2,op,s,d,x,y;
int a[N];
ll ivr1[N],ivr2[N];
ll I[N],II[N];
inline ll Pow(ll a,ll b,ll mod){
ll d=1,t=a;
while(b){
if(b&1) d=d*t%mod;
b>>=1;
t=t*t%mod;
}
return d;
}
struct node{
int lch,rch;
ll sum,A;
ll la,lb,laa,lbb;
ll s1,s2;
}root[N<<2];
inline void init(){
clr(ivr1),clr(ivr2);
if(r%p1!=0){
rep(i,1,n+1){
ivr1[i]=Pow(r,i*1LL*(p1-2)%(p1-1),p1);
}
}
if(r%p2!=0){
rep(i,1,n+1){
ivr2[i]=Pow(r,i*1LL*(p2-2)%(p2-1),p2);
}
}
I[0]=II[0]=0;
I[1]=r%p1,II[1]=r%p1;
ll p=r%p1;
rep(i,2,n+1) {
p*=r,p%=p1;
I[i]=I[i-1]+p;
II[i]=II[i-1]+p*i%p1;
I[i]%=p1,II[i]%=p1;
}//sigma(r^i)%p1 and sigma(i*r^i)%p1
}
inline void change_sum(int t,ll a,ll b){
root[t].sum += (a*root[t].s1%p1 + b*root[t].s2%p1)%p1;
root[t].sum %= p1;
}
inline void push_up(int t){
root[t].sum = (root[L].sum+root[R].sum)%p1;
}
inline void change1(int t,ll a,ll b){
root[t].la+=a;root[t].la%=p1;
root[t].lb+=b;root[t].lb%=p1;
change_sum(t,a,b);
}
inline void change2(int t,ll a,ll b){
root[t].laa+=a;root[t].laa%=p2;
root[t].lbb+=b;root[t].lbb%=p2;
}
inline void push_down1(int t){
if(root[t].la!=0 || root[t].lb!=0){
change1(L,root[t].la,root[t].lb);
change1(R,root[t].la,root[t].lb);
root[t].la=root[t].lb=0;
}
}
inline void push_down2(int t){
if(root[t].laa!=0 || root[t].lbb!=0){
change2(L,root[t].laa,root[t].lbb);
change2(R,root[t].laa,root[t].lbb);
root[t].laa=root[t].lbb=0;
}
}
inline void build(int t,int x,int y){
root[t].lch=x,root[t].rch=y;
root[t].sum=root[t].A=0;
root[t].la=root[t].lb=0;
root[t].laa=root[t].lbb=0;
root[t].s1=((I[y]-I[x-1])%p1+p1)%p1;
root[t].s2=((II[y]-II[x-1])%p1+p1)%p1;
if(x==y){
root[t].sum=a[x]%p1;
root[t].A=a[x]%p2;
return;
}
else{
int mid=(x+y)/2;
build(L,x,mid),build(R,mid+1,y);
push_up(t);
}
}
inline void modefiy(int t,int x,int y,int s,int d,int x1){
int lch=root[t].lch,rch=root[t].rch;
if(lch>=x && rch<=y){
ll v1=(((s-d*1LL*x1)%p1+p1)%p1*ivr1[x1]%p1+p1)%p1;
ll v2=d*1LL*ivr1[x1]%p1;
root[t].la+=v1,root[t].la%=p1;
root[t].lb+=v2,root[t].lb%=p1;
change_sum(t,v1,v2);
v1=(((s-d*1LL*x1)%p2+p2)%p2*ivr2[x1]%p2+p2)%p2;
v2=d*1LL*ivr2[x1]%p2;
root[t].laa+=v1,root[t].laa%=p2;
root[t].lbb+=v2,root[t].lbb%=p2;
return;
}
push_down1(t);
push_down2(t);
int mid=(lch+rch)/2;
if(y<=mid) modefiy(L,x,y,s,d,x1);
else if(x>mid) modefiy(R,x,y,s,d,x1);
else{
modefiy(L,x,mid,s,d,x1),modefiy(R,mid+1,y,s,d,x1);
}
push_up(t);
}
inline void modefiy(int t,int x,int val){
int lch=root[t].lch,rch=root[t].rch;
if(lch == rch){
ll vv=Pow(r,lch%(p2-1),p2);
root[t].A += (root[t].laa*vv%p2+root[t].lbb*lch%p2*vv%p2)%p2;
root[t].A+=val%p2;
root[t].sum+=val%p1;
root[t].A%=p2;
root[t].sum%=p1;
root[t].laa=root[t].lbb=root[t].la=root[t].lb=0;
return;
}
push_down1(t);
push_down2(t);
int mid=(lch+rch)/2;
if(x<=mid) modefiy(L,x,val);
else modefiy(R,x,val);
push_up(t);
}
inline void addPow(int t,int x,int val){
int lch=root[t].lch,rch=root[t].rch;
if(lch == rch){
ll vv=Pow(r,lch%(p2-1),p2);
root[t].A += (root[t].laa*vv%p2+root[t].lbb*lch%p2*vv%p2)%p2;
root[t].A %= p2;
root[t].A = Pow(root[t].A,val,p2);
root[t].sum=root[t].A%p1;
root[t].laa=root[t].lbb=root[t].la=root[t].lb=0;
return;
}
push_down1(t);
push_down2(t);
ll mid=(lch+rch)/2;
if(x<=mid) addPow(L,x,val);
else addPow(R,x,val);
push_up(t);
}
inline ll query(int t,int x,int y){
int lch=root[t].lch,rch=root[t].rch;
if(lch>=x && rch<=y){
return root[t].sum%p1;
}
push_down1(t);
push_down2(t);
int mid=(lch+rch)/2;
if(y<=mid) return query(L,x,y);
else if(x>mid) return query(R,x,y);
else{
return (query(L,x,mid)+query(R,mid+1,y))%p1;
}
}
inline int input(){
int ret=0;bool isN=0;char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') isN=1;
c=getchar();
}
while(c>='0' && c<='9'){
ret=ret*10+c-'0';c=getchar();
}
return isN?-ret:ret;
}
int main(){
//freopen("in","r",stdin);
//freopen("out","w",stdout);
t=input();
while(t--){
n=input(),q=input(),r=input(),p1=input(),p2=input();
rep(i,1,n+1) a[i]=input();
init();
build(1,1,n);
while(q--){
op=input();
if(op==0){
s=input();
d=input();
x=input();
y=input();
modefiy(1,x,s);
if(x+1<=y) modefiy(1,x+1,y,s,d,x);
}
else if(op==1){
x=input(),y=input();
addPow(1,x,y);
}
else{
x=input(),y=input();
ll ans=query(1,x,y);
printf("%lld\n",(ans%p1+p1)%p1);
}
}
}
return 0;
}
啊啊啊啊,不会做,赛后看了别人的代码,才知道自己多弱。。。。。对于最积极和随机都用的记忆化搜索,dp[i][g]表示剩余i张牌,gcd是g的概率。
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
#define rep(i,s,t) for(int i=s;i<t;i++)
#define N 110
inline int input(){
int ret=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9'){
ret=ret*10+c-'0';
c=getchar();
}
return ret;
}
int t,n,a[N],map[N][N];
bool vis[N],tag;
int win[N][N];
double dp[N][N];
inline int gcd(int a,int b){
if(!a) return b;
if(!b) return a;
return gcd(b,a%b);
}
inline bool dfs1(int cnt,int g){
if(win[cnt][g]!=-1) return win[cnt][g];
if(cnt==0) return win[cnt][g]=0;
int ans=0;
rep(i,0,n){
if(!vis[i]){
int x=map[a[i]][g];
if(x!=1){
vis[i]=1;
if(!dfs1(cnt-1,x)){
ans=1;
}
vis[i]=0;
}
}
if(ans) break;
}
return win[cnt][g]=ans;
}
inline double dfs2(int cnt,int g){
if(dp[cnt][g]!=-1) return dp[cnt][g];
if(cnt==0) return dp[cnt][g]=0;
double ans=0;
rep(i,0,n){
if(!vis[i]){
int x=map[a[i]][g];
if(x!=1){
vis[i]=1;
ans+=(1-dfs2(cnt-1,x))/cnt;
vis[i]=0;
}
}
}
return dp[cnt][g]=ans;
}
int main(){
//freopen("in","r",stdin);
//freopen("out","w",stdout);
rep(i,0,101) rep(j,0,101) map[i][j]=gcd(i,j);
t=input();
while(t--){
n=input();
rep(i,0,n) a[i]=input();
rep(i,0,N) rep(j,0,N){
dp[i][j]=-1;win[i][j]=-1;
}
clr(vis);
if(dfs1(n,0)==1) printf("1 ");
else printf("0 ");
clr(vis);
printf("%.4lf\n",dfs2(n,0));
}
}