头文件见上一场的blog
A题:cf 632B
题意:详情见我上上篇文章(个人排位div2#3
题解:同上
代码:同上
B题:cf 627A
题意:给你s和x,可能存在正数a+b=s,且a xor b=x,问a,b可能的组合有多少种
题解:s=a+b,则s=a ^ b+2*(a&b),^是只表示两个数的相加,&是表示两个数的进位,某一位的xor如果是1,那么a和b在这一位必然一个是1一个是0,此时&必为0;如果某一位的xor是0,那么在这一位的a和b都是确定的要么都是1要么都是0,至于是哪个,这个由其他位决定,所以不用管它们
ac代码:
int main()
{
#ifdef local
freopen("in.txt", "r", stdin);
#endif // local
ll s,x,ans=1;
scanf("%lld%lld",&s,&x);
ll a=(s-x)/2;
if(a<0||(a*2+x)!=s||(a&x)!=0)
{
printf("0");
}
else{//printf("okkk");
ll t=0;
while(x)
{
if(x%2==1)ans*=2;
x>>=1;
}
if(a==0)ans=ans-2;
printf("%lld",ans);
}
return 0;
}
C题:cf 623A
题意:有一个字符串,只包含a,b,c,每一个字符都可以和b相连,a,c只能和自己相连,给出所有的字符相互连接情况,复原该字符串(字符串可能不存在
题解:二分图染色——显然ac之间不能连接,其实作题目的补图,这个补图就是二分图了!标记所有连接情况,发现某个点和其他点都连接,填写b,然后往下填,优先填a,如果有连接的格子,也填a,不连接的话,填c。违规情况有两种:i和j连接,但是一个填了a一个填了c;i和j没有链接,但是他们填的是一样的字母
ac代码:
int n,m,flag=0;
int s[800][800];
char ans[600];
void dfs(int i)
{
for(int j=0;j<n;j++)
{
if(i!=j&&s[i][j]==0&&ans[i]==ans[j])
{
flag=1;
}
if(i!=j&&s[i][j]==1&&((ans[i]=='a'&&ans[j]=='c')||(ans[i]=='c'&&ans[j]=='a')))
{
flag=1;
}
if(i!=j&&s[i][j]==0&&ans[j]==0)
{
if(ans[i]=='a')ans[j]='c';
else if(ans[i]=='c')ans[j]='a';
dfs(j);
}
if(i!=j&&s[i][j]==1&&ans[j]==0)
{
if(ans[i]=='a')ans[j]='a';
else if(ans[i]=='c')ans[j]='c';
dfs(j);
}
}
}
int main()
{
#ifdef local
freopen("in.txt", "r", stdin);
#endif // local
scanf("%d%d",&n,&m);
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
s[a-1][b-1]=1;
s[b-1][a-1]=1;
}
for(int i=0;i<n;i++)
{
int po=0;
for(int j=0;j<n;j++)
{
if(i!=j&&s[i][j]==0)
po=1;
}
if(po==0)
ans[i]='b';
}
for(int i=0;i<n;i++)
{
if(ans[i]==0){
ans[i]='a';
dfs(i);
}
}
if(flag==1)printf("No");
else {
printf("Yes\n");
printf("%s",ans);
}
return 0;
}
D题:cf 604B
题意:n个铃铛,m个箱子,n<=2m,铃铛体积从第一个到最后一个递增,问要装下所有的铃铛,箱子体积统一,那么箱子最小要有多大
题解:由题意得,设有x个铃铛单独装箱,x=2m-n,这x个肯定是取最大的那几个放,剩下的里面最大+最小为一箱,不断更新箱子体积就可以了
ac代码:
int a[150000];
int main()
{
#ifdef local
freopen("in.txt", "r", stdin);
#endif // local
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)scanf("%d",&a[i]);
if(m>=n)printf("%d",a[n-1]);
else{
int cnt,ans=a[n-1];
cnt=2*m-n;
cnt=n-cnt;
for(int i=0;i<=cnt/2;i++)
ans=max(ans,a[i]+a[cnt-i-1]);
printf("%d",ans);
}
return 0;
}
E题:hdu 2098
题意:给你一个偶数,拆成两个素数的解,问有多少种拆法
题解:暴力求解就好啦(嚣张
ac代码:
bool prime(int n)
{
if(n==2)return false;
else if(n>2)
{
for(int i=2;i*i<=n;i++)
{
if(n%i==0)return false;
}
return true;
}
}
int main()
{
#ifdef local
freopen("in.txt", "r", stdin);
#endif // local
int n;
while(scanf("%d",&n)!=EOF)
{
if(n==0)break;
else
{
int ans=0;
for(int i=2;i<n/2;i++)
if(prime(i)&&prime(n-i))
ans++;
printf("%d\n",ans);
}
}
return 0;
}
F题:poj 3259
题意:一个人从点1出发,走路经过若干条路去到某个点,再经由这个点走虫洞(可能不止一个)或者走路回到点1,且用时比去的时候少,问存在这种情况吗
题解:Bellman_Ford,负权有向图(是叫这个吗),就是维护每个点到源点的距离,如果这个点到源点的用时少于它的来点+走到它的用时,说明存在情况
ac代码:
int T,n,m,k;
struct NODE
{
int from,to,dist;
};
vector<NODE>edge;
vector<int>g[1000];
void good(int n)
{
for(int i=0;i<n;i++)g[i].clear();
edge.clear();
}
void addnode(int from,int to,int dist)
{
edge.push_back((NODE){from,to,dist});
int k=edge.size();
g[from].push_back(k-1);
}
bool BELLMAN_FORD(int s)
{
int d[1000];
for(int i=0;i<n;i++)d[i]=(i==s?0:inf);
for(int i=1;i<n;i++)
{
for(int j=0;j<edge.size();j++)
{
NODE e=edge[j];
if(d[e.from]<inf)
d[e.to]=min(d[e.to],d[e.from]+e.dist);
}
}
for(int i=0;i<edge.size();i++)
{
NODE e=edge[i];
if(d[e.to]>d[e.from]+e.dist)return true;
}
return false;
}
int main()
{
#ifdef local
freopen("in.txt", "r", stdin);
#endif // local
scanf("%d",&T);
while(T--)
{
good(n);
scanf("%d%d%d",&n,&m,&k);
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
addnode(a-1,b-1,c);
addnode(b-1,a-1,c);
}
while(k--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
addnode(a-1,b-1,-c);
}
if(BELLMAN_FORD(0))printf("YES\n");
else printf("NO\n");
}
return 0;
}
G题:cf 474D
题意:k的白花规模数,一把花有a~b朵花,一把花里的花可以是红花,或者红花+k*n朵白花(n>=0);且每一个k朵白花必须全部相连,比如说一把花有4朵,红花是R白花是W,这把花可以是RRWW,不可以是WRWR。给出a,b问有多少种花的组合方法
题解:DP,状态转移方程是:dp[i]=dp[i-1]+dp[i-k],dp[i-1]对应的是i位是红花的情况,dp[i-k]对应的是第i位是白花的情况,如果i是白花,那么i-k+1~i都是白花,dp[i]是对前面情况的继承
ac代码:
ll dp[101000],ans[101000];
int main()
{
#ifdef local
freopen("in.txt", "r", stdin);
#endif // local
int n,k,a,b;
while(scanf("%d%d",&n,&k)!=EOF)
{
memset(dp,0,sizeof(dp));
memset(ans,0,sizeof(ans));
dp[0]=1;
for(int i=1;i<=100005;i++)
{
if(i>=k)dp[i]=(dp[i-1]+dp[i-k])%mod;
else dp[i]=dp[i-1];
}
for(int i=1;i<=100005;i++)
{
ans[i]=(ans[i-1]+dp[i])%mod;
}
//for(int i=1;i<=5;i++)printf("**%lld %lld",dp[i],dp[])
while(n--)
{
scanf("%d%d",&a,&b);
ll sum=0;
sum=(ans[b]-ans[a-1]+mod)%mod;
printf("%lld\n",sum);
}
}
return 0;
}
H题:hdu 1166
题意:有n个营地,每个营地有若干个士兵,可以对这些营地进行加兵,减兵,数兵的操作,数兵会给出范围a~b,数兵的时候输出总数
题解:线段树维护局部和,板子题
我学习的线段树模板来自:点进去就好啦
ac代码:
const int maxn=500010*4;
using namespace std;
int a[maxn];
struct TREE
{
int l,r,sum;
}node[maxn];
void pushup(int i)
{
node[i].sum=node[i<<1].sum+node[(i<<1)|1].sum;
}
void build(int i,int l,int r)
{
node[i].l=l;node[i].r=r;
if(l==r)
{
node[i].sum=a[l];return;
}
int mid=(l+r)/2;
build(i<<1,l,mid);
build((i<<1)|1,mid+1,r);
pushup(i);
}
int getsum(int i,int l,int r)
{
if(node[i].l==l&&node[i].r==r)return node[i].sum;
int mid=(node[i].l+node[i].r)/2;
if(r<=mid)return getsum(i<<1,l,r);
else if(l>mid)return getsum((i<<1)|1,l,r);
else return (getsum(i<<1,l,mid)+getsum((i<<1)|1,mid+1,r));
}
void add(int i,int k,int v)
{
if(node[i].l==k&&k==node[i].r){node[i].sum+=v;return;}
int mid=(node[i].l+node[i].r)/2;
if(k<=mid) add(i<<1,k,v);
else add((i<<1)|1,k,v);
pushup(i);
}
int main()
{
#ifdef local
freopen("in.txt", "r", stdin);
#endif // local
int T,cas=1;
scanf("%d",&T);
while(T--)
{
memset(a,0,sizeof(a));
int n;
scanf("%d",&n);getchar();
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
build(1,1,n);
int k,v;
char s[10];
printf("Case %d:\n",cas++);
while(scanf("%s",s)!=EOF)
{
if(s[0]=='E')break;
scanf("%d%d",&k,&v);
if(s[0]=='A')add(1,k,v);
if(s[0]=='S')add(1,k,-v);
if(s[0]=='Q')printf("%d\n",getsum(1,k,v));
getchar();
}
}
return 0;
}