T1
考场上一看到暴力有70分就没有去想正解。当时脑子里闪过了先处理两个相加,再询问。但是当时感觉可能会算重复,就没有继续往下想。
但是应该是没有重复的。因为顺序不同也算不同方案。。
因为100000内的质数只有9000多个,所以可以定义dp[i]为i能被两个质数相加得到的方案数。然后(n^2)求出。
对于每个n,只需O(n)求出答案即可。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100000+10;
int read(){
int w=0,x=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') x=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
w=(w<<1)+(w<<3)+(ch^48);
ch=getchar();
}
return x*w;
}
int n,cnt;
int prime[maxn];
bool is_not_prime[maxn];
ll dp[maxn<<1];
ll ans;
void xxs(){
is_not_prime[0]=is_not_prime[1]=1;
for(register int i=2;i<=100000;++i){
if(!is_not_prime[i]) prime[++cnt]=i;
for(register int j=1;j<=cnt&&i*prime[j]<=100000;++j){
is_not_prime[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
for(register int i=1;i<=cnt;++i){
for(register int j=1;j<=cnt;++j){
if(prime[i]+prime[j]<=100000) dp[prime[i]+prime[j]]++;
}
}
}
void Solve(){
xxs();
int T=read();
while(T--){
n=read();
ll ans=0;
for(register int i=1;i<=n;++i) ans+=dp[i]*dp[n-i];
printf("%lld
",ans);
}
}
int main(){
freopen("plus.in","r",stdin);
freopen("plus.out","w",stdout);
Solve();
return 0;
}
T2
转化为01trie。发现对于[l,r],假如两个区间[l,mid],[mid+1,r]完全相同,那么就是这一位取0或1都行于是返回F(l,mid)2。
如果两个区间没有交,那么就是分开讨论,再相乘,即F(l,mid+1)F(mid+1,r);
如果两种情况都没出现,那么一定无解。
边界F(x,x)=1;
(其实可以先在OJ上交一发printf('0');,然后发现0分,证明没有无解的情况,于是每次比较两个区间的时候只需要比较第一个元素即可,然后就跑成了最优解233)
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1<<17,mod=1e9+7;
#define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? EOF : *p1++) : *p1++)
#define read() ({ register int x = 0, f = 1; register char c = gc(); while(c < '0' || c > '9') { if (c == '-') f = -1; c = gc();} while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc(); f * x; })
char buf[1 << 20], *p1, *p2;
int m,n;
int p[maxn];
int ans;
int Devide(int l,int r){
if(l==r) return 1;
int mid=(l+r)>>1;
bool flag=0;
if(p[l]==p[mid+1]) return 2*Devide(l,mid)%mod;
return 1ll*Devide(l,mid)*Devide(mid+1,r)%mod;
}
void Solve(){
m=read();
n=read();
for(int i=1;i<=(1<<m);++i) p[i]=read();
ans=Devide(1,1<<m);
printf("%d
",ans);
}
int main(){
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
Solve();
return 0;
}
T3
这题转化完了之后竟然是原题。。操
发现一条边是黑边的条件,就是两个端点被不同的修改操作修改过。
因此可以打时间戳,最后询问路径有多少连续相等的段。
于是就是luogu P2486 [SDOI2011]染色了,具体怎么维护链接里有。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=500000+10,Inf=0x3f3f3f3f;
struct node{
int to,next;
}edge[maxn<<1];
int head[maxn],top[maxn],size[maxn],son[maxn],fa[maxn],depth[maxn],dfn[maxn];
int n,m,cnt,Time,tim;
struct Segment_tree{
int val,lazy,lc,rc;//lc,rc分别表示这个区间左右端点的color,lazy==-1时表示没有赋值
}tree[maxn<<2];
int read(){
int w=0,x=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') x=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
w=(w<<1)+(w<<3)+(ch^48);
ch=getchar();
}
return x*w;
}
void add(int from,int to){
edge[++cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
}
void dfs1(int u,int f){
size[u]=1;
fa[u]=f;
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(v==f) continue;
depth[v]=depth[u]+1;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t){
top[u]=t;
dfn[u]=++Time;
if(son[u]) dfs2(son[u],t);
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
}
void pushup(int rt){
tree[rt].lc=tree[rt<<1].lc;
tree[rt].rc=tree[rt<<1|1].rc;
tree[rt].val=tree[rt<<1].val+tree[rt<<1|1].val-(tree[rt<<1].rc==tree[rt<<1|1].lc);
}
void update(int rt,int x){
tree[rt].lazy=x;
tree[rt].val=1;
tree[rt].lc=tree[rt].rc=x;
}
void pushdown(int rt){
if(tree[rt].lazy==-1) return;
tree[rt].val=1;
update(rt<<1,tree[rt].lazy);
update(rt<<1|1,tree[rt].lazy);
tree[rt].lazy=-1;
}
void modify(int rt,int l,int r,int s,int t,int p){
if(s<=l&&r<=t){
update(rt,p);
return;
}
int mid=(l+r)>>1;
pushdown(rt);
if(s<=mid) modify(rt<<1,l,mid,s,t,p);
if(t>mid) modify(rt<<1|1,mid+1,r,s,t,p);
pushup(rt);
}
void build(int rt,int l,int r){
tree[rt].lazy=-1;
if(l==r){
tree[rt].val=1;
tree[rt].lc=tree[rt].rc=l;
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
int query2(int rt,int l,int r,int x){
if(l==r) return tree[rt].lc;
int mid=(l+r)>>1;
pushdown(rt);
if(x<=mid) return query2(rt<<1,l,mid,x);
else return query2(rt<<1|1,mid+1,r,x);
}
int query(int rt,int l,int r,int s,int t){
if(s<=l&&r<=t) return tree[rt].val;
int mid=(l+r)>>1;
pushdown(rt);
if(t<=mid) return query(rt<<1,l,mid,s,t);
if(s>mid) return query(rt<<1|1,mid+1,r,s,t);
return query(rt<<1,l,mid,s,t)+query(rt<<1|1,mid+1,r,s,t)-(tree[rt<<1].rc==tree[rt<<1|1].lc);
}
int Query(int u,int v){
if(u==v) return 1;
int res=0;
while(top[u]!=top[v]){
if(depth[top[u]]<depth[top[v]]) swap(u,v);
//printf("u==%d v==%d
",u,v);
res+=query(1,1,n,dfn[top[u]],dfn[u]);
//printf("dfn[top[u]]=%d dfn[u]=%d
",dfn[top[u]],dfn[u]);
if(top[u]!=1){
int sss=query2(1,1,n,dfn[top[u]]);
int ssss=query2(1,1,n,dfn[fa[top[u]]]);
//printf("sss=%d ssss=%d
",sss,ssss);
if(sss==ssss) res--;
//if(top[u]!=1 && query2(1,1,n,dfn[top[u]])==query2(1,1,n,dfn[fa[top[u]]])) res--;
}
u=fa[top[u]];
}
if(depth[u]>depth[v]) swap(u,v);
res+=query(1,1,n,dfn[u],dfn[v]);
return res;
}
void Modify(int u,int v,int x){
while(top[u]!=top[v]){
if(depth[top[u]]<depth[top[v]]) swap(u,v);
modify(1,1,n,dfn[top[u]],dfn[u],x);
u=fa[top[u]];
}
if(depth[u]>depth[v]) swap(u,v);
modify(1,1,n,dfn[u],dfn[v],x);
}
void Solve(){
n=read();
for(int i=1,x,y;i<n;++i){
x=read();
y=read();
add(x,y);
add(y,x);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
//for(int i=1;i<=n;++i) printf("fa[%d]=%d son[%d]=%d depth[%d]=%d top[%d]=%d size[%d]=%d dfn[%d]=%d
",i,fa[i],i,son[i],i,depth[i],i,top[i],i,size[i],i,dfn[i]);
m=read();
tim=n;
for(int i=1,op,x,y,z;i<=m;++i){
op=read();
x=read();
y=read();
if(op==0){
int res=Query(x,y);
printf("%d
",res-1);
}
else{
tim++;
Modify(x,y,tim);
}
}
}
int main(){
freopen("colour.in","r",stdin);
freopen("colour.out","w",stdout);
Solve();
return 0;
}
T4
不会