CodeChef May Challenge 2014

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));
	}
} 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值