Description:
有 n n n堆石子,第 i i i堆的石子个数为 i i i,两人可以每次可以在其中一堆中拿任意数量的石子,无法再继续拿为败。求必胜的方案数。
n ≤ 1 0 1000 n\le 10^{1000} n≤101000
Solution:
Code:
#include
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i=i##_end_;--i)
#define ll long long
#define N 1002
#define L 255
#define P 10000
struct Big{
int num[L],len;
Big(){
memset(num,0,sizeof(num));
len=1;
}
void Rd(){
char A[N];
scanf("%s",A);
int SL=strlen(A);
len=0;
for(int i=SL-1,res;res=0,i>=0;num[len++]=res,i-=4){
if(i>=3)for(int j=i-3;j<=i;j++)res=(res<<1)+(res<<3)+(A[j]^48);
else for(int j=0;j<=i;j++)res=(res<<1)+(res<<3)+(A[j]^48);
}
}
void Pr(){
if(!num[len-1]){putchar('0');return;}
printf("%d",num[len-1]);
DREP(i,len-2,0)printf("%04d",num[i]);
}
Big operator +(const Big &a)const{
Big b;
b.len=max(len,a.len);
REP(i,0,b.len-1){
int &B=b.num[i];
B+=num[i]+a.num[i];
if(B>=P)B-=P,b.num[i+1]++;
}
if(b.num[b.len])b.len++;
return b;
}
Big operator+(int a){
Big b;
b.len=len;
REP(i,0,len-1){
int &B=b.num[i];
B+=num[i]+a%P;
if(B>=P)b.num[i+1]++,B-=P;
a/=P;
}
if(b.num[b.len])b.len++;
return b;
}
Big operator -(const Big &a)const{
Big b;
REP(i,0,len-1)b.num[i]=num[i];
b.len=len;
DREP(i,a.len-1,0){
b.num[i]-=a.num[i];
int now=i;
while(b.num[now]<0)b.num[now]+=P,now++,b.num[now]--;
}
while(b.len>1 && !b.num[b.len-1])b.len--;
return b;
}
Big operator *(const int &a)const{
Big b;
b.len=len;
REP(i,0,len-1){
int &B=b.num[i];
B+=num[i]*a;
if(B>=P)b.num[i+1]+=B/P,B%=P;
}
if(b.num[b.len])b.len++;
return b;
}
Big operator /(const int &a)const{
Big b;
REP(i,0,len-1)b.num[i]=num[i];
DREP(i,len-1,1)b.num[i-1]+=b.num[i]%a*P,b.num[i]/=a;
b.num[0]/=a;
b.len=len;
while(b.len>1 && !b.num[b.len-1])b.len--;
return b;
}
bool operator<=(const Big &a)const{
if(len!=a.len)return len>cas;
Big n;
while(cas--){
n.Rd();
if(n.num[0]&1){
n=n+1;
n=n/2;
if(n.num[0]&1)n.Pr();
else putchar('0');
}
else {
Big mx;
mx=mx+1;
while(mx<=n)mx=mx*2;
mx=mx/2;
n=n-mx+1;
n.Pr();
}
puts("");
}
return 0;
}
Description:
一个长度为 n n n的序列 A A A,现在想求出有多少对区间 [ a , b ] [a,b] [a,b]与区间 [ c , d ] [c,d] [c,d],满足不存在一个数在 { A a , A a + 1 , . . . , A b − 1 , A b } \{A_a,A_{a+1},...,A_{b-1},A_b\} {Aa,Aa+1,...,Ab−1,Ab}和 { A c , A c + 1 , . . . , A d − 1 , A d } \{A_c,A_{c+1},...,A_{d-1},A_d\} {Ac,Ac+1,...,Ad−1,Ad}中同时出现。
n ≤ 3000 , 1 ≤ A i ≤ 1 0 9 n\le3000,1\le A_i\le 10^9 n≤3000,1≤Ai≤109
Solution:
Code:
#include
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i=i##_end_;--i)
#define ll long long
const int N=3002;
int n;
int A[N];
struct p30{
mapmp;
void solve(){
int ans=0;
REP(a,1,n) REP(b,a,n) {
mp.clear();
REP(i,a,b) mp[A[i]]++;
REP(c,b+1,n) REP(d,c,n){
bool flag=1;
REP(j,c,d) if(mp[A[j]]){flag=0;break;}
ans+=flag;
}
}
printf("%d\n",ans);
}
}p1;
struct p100{
int tmp[N];
vectorpos[N];
int cnt[N];
int pre[N],nxt[N];
int val[N];
void solve(){
memcpy(tmp,A,sizeof(tmp));
sort(tmp+1,tmp+1+n);
REP(i,1,n) {
A[i]=upper_bound(tmp+1,tmp+1+n,A[i])-tmp-1;
pos[A[i]].push_back(i);
}
REP(i,1,n) val[i]=i*(i+1)/2;
ll ans=0;
REP(i,2,n){
REP(j,1,n) cnt[j]=0;
REP(j,i,n) cnt[A[j]]++;
int last=0;
REP(j,1,i) if(cnt[A[j]]){
nxt[last]=j;
pre[j]=last;
last=j;
}
ll sum=0;
for(int j=0;j=i)break;
int L=pre[x],R=nxt[x];
sum-=val[R-x-1];
sum-=val[x-L-1];
pre[R]=L,nxt[L]=R;
sum+=val[R-L-1];
}
}
ans+=sum;
}
}
printf("%lld\n",ans);
}
}p2;
int main(){
// freopen("segment.in","r",stdin);
// freopen("segment.out","w",stdout);
scanf("%d",&n);
REP(i,1,n) scanf("%d",&A[i]);
if(n<=20)p1.solve();
else p2.solve();
return 0;
}
Description:
NOI 2006 网络收费
Solution:
Code:
#include
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);iinline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
const int N=(1<<11)+2,INF=0x3f3f3f3f;
int n,m;
int T[N],C[N],F[N][N];
int cost[N][N];
int dp[N][N];
int Pow[12];
int Lca(int x,int y){
while(x!=y)x>>=1,y>>=1;
return x;
}
void solve(int p,int dep){
if(!dep){
dp[p][T[p]]=0,dp[p][!T[p]]=C[p];
for(int i=p>>1;i;i>>=1) dp[p][T[i]]+=cost[i][p];
return;
}
memset(dp[p],63,sizeof(dp[p]));
T[p]=0;
solve(p<<1,dep-1),solve(p<<1|1,dep-1);
REP(i,1,Pow[dep-1]) REP(j,Pow[dep-1]-i+1,Pow[dep]-i) chkmin(dp[p][i+j],dp[p<<1][i]+dp[p<<1|1][j]);
T[p]=1;
solve(p<<1,dep-1),solve(p<<1|1,dep-1);
REP(i,0,Pow[dep-1]) REP(j,0,Pow[dep-1]-i) chkmin(dp[p][i+j],dp[p<<1][i]+dp[p<<1|1][j]);
}
int main(){
// freopen("network.in","r",stdin);
// freopen("network.out","w",stdout);
scanf("%d",&n);
Pow[0]=1;
REP(i,1,10) Pow[i]=Pow[i-1]+Pow[i-1];
REP(i,1,Pow[n]) scanf("%d",&T[i+Pow[n]-1]);
REP(i,1,Pow[n]) scanf("%d",&C[i+Pow[n]-1]);
SREP(i,1,Pow[n]) REP(j,i+1,Pow[n]){
int x=i+Pow[n]-1,y=j+Pow[n]-1;
scanf("%d",&F[x][y]);
int lca=Lca(x,y);
cost[lca][x]+=F[x][y],cost[lca][y]+=F[x][y];
}
solve(1,n);
int ans=INF;
REP(i,0,Pow[n]) chkmin(ans,dp[1][i]);
printf("%d\n",ans);
return 0;
}