寫在前面:這場的題目感覺比前兩場的難,最後苟了個七題,BEJ估計明天再補吧。現在更新一下已經過了的七道題。
A-牛牛的DRB迷宮I
題意:給出一個的迷宮,每一格有三種情況,分別是向下移動,向右移動,可以向下也可以向右移動。
題解:顯然的dp題。當時,當時,當時。最後輸出即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
ll f[100][100];
int n,m;
char s[100][100];
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)scanf("%s",&s[i]);
f[0][0]=1ll;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(s[i][j]=='D')f[i+1][j]=(f[i+1][j]+f[i][j])%mod;
else if(s[i][j]=='R')f[i][j+1]=(f[i][j+1]+f[i][j])%mod;
else if(s[i][j]=='B')f[i+1][j]=(f[i+1][j]+f[i][j])%mod,f[i][j+1]=(f[i][j+1]+f[i][j])%mod;
printf("%lld\n",f[n-1][m-1]);
return 0;
}
C-牛牛的數組越位
題意:題目描述了一下數組越界的概念,具體自己看題目介紹吧。
題解:按照題意模擬即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e7+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
int n,m,p;
int G[1010][1010];
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&p);
int fflag=0,ffflag=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)G[i][j]=0;
while(p--){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
int k=m*x+y;
if(!ffflag){
if(k<0 || k>=n*m){ffflag=1;continue;}
if(x<0 || y<0 || x>=n || y>=m){fflag=1;}
int yy=k%m,xx=k/m;
G[xx][yy]=z;
}
}
if(ffflag){
puts("Runtime error");
continue;
}
for(int i=0;i<n;i++){
for(int j=0;j<m-1;j++)printf("%d ",G[i][j]);
printf("%d\n",G[i][m-1]);
}
if(fflag)puts("Undefined Behaviour");
else puts("Accepted");
}
return 0;
}
D-牛牛與二叉樹的數組存儲
題意:題目描述了一下數組存儲二叉樹的概念,具體自己看題目介紹即可。
題解:按照題意模擬即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
int n,a[2*maxn],f[maxn*2],sum;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),f[a[i]]=i;
for(int i=1;i<=n;i++)if(a[i]!=-1)sum++;
for(int i=n+1;i<=n*2+1;i++)a[i]=-1;
a[0]=-1;
printf("The size of the tree is %d\n",sum);
printf("Node %d is the root node of the tree\n",a[1]);
for(int i=1;i<=sum;i++){
printf("The father of node %d is %d, the left child is %d, and the right child is %d\n",i,a[f[i]/2],a[f[i]*2],a[f[i]*2+1]);
}
return 0;
}
F-牛牛的Link Power I
題意:給出一個長度爲n的01串,設,則答案需要加上,算出所有的1對對答案的貢獻即可。
題解:可以亂搞,方法很多。開一個數組記錄所有1的位置,記錄一下所有的和sum,再用一個cnt表示當前有多少個1,每次對答案的貢獻就是當前的a[i]*cnt-sum。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
int n,cnt,num;
ll sum,ans;
int q[maxn];
char a[maxn];
int main(){
scanf("%d",&n);
scanf("%s",&a);
for(int i=0;i<n;i++)
if(a[i]=='1'){
q[++cnt]=i;
sum=sum+1ll*i;
}
for(int i=cnt;i>0;i--){
sum=sum-1ll*q[i];num++;
ans=(ans+1ll*(cnt-num)*q[i]-sum)%mod;
}
printf("%lld\n",ans);
return 0;
}
H-牛牛的k合因子數
題意:一個正整數,如果有k個合數因子則被稱爲k合因子數。m個詢問,每次問1~n中有多少個k合因子數。
題解:篩法。先篩出1e5全部的素數,然後再用篩法類似的累加一下貢獻即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
int f[maxn],ans[maxn],a[maxn];
int n,m,k;
int main(){
for(int i=2;i<=100000;i++)
if(!f[i])
for(int j=i*2;j<=100000;j+=i)f[j]++;
for(int i=2;i<=100000;i++)
if(f[i])
for(int j=i;j<=100000;j+=i)a[j]++;
// printf("%d\n",a[20]);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)ans[a[i]]++;
while(m--){
scanf("%d",&k);
printf("%d\n",ans[k]);
}
return 0;
}
G-牛牛的Link Power II
題意:F題題意,但是帶修。保證一定是將1改成0,0改成1。每次輸出修改後的總答案。
題解:先計算出答案,對於維護我們使用線段樹,維護區間1的個數和1的位置總和。若將0變1相當於增加一波貢獻,若將1變0相當於減去一波貢獻。假設k1和k2分別是[1,pos-1],[pos+1,n]的區間結點。對於答案就應該分別加上或減去
#include "stdio.h"
#include "string.h"
#include "iostream"
#include "algorithm"
#include "stack"
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const ll mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
struct Node{
ll sum;
int num;
}s[maxn*4],res;
stack<int>q;
struct arr{
int pos,val;
}a[maxn];
Node cmp(Node a,Node c){
Node k;
k.num=(a.num%mod+c.num%mod)%mod;
k.sum=(a.sum%mod+c.sum%mod)%mod;
return k;
}
void pushup(int node){
s[node].sum=(s[node<<1].sum%mod+s[node<<1|1].sum%mod)%mod;
s[node].num=(s[node<<1].num%mod+s[node<<1|1].num%mod)%mod;
return;
}
void build(int l,int r,int node){
if(l==r){
s[node].num=a[l].pos;
s[node].sum=a[l].val;
return;
}
int mid=(l+r)>>1;
build(l,mid,node<<1);
build(mid+1,r,node<<1|1);
pushup(node);
}
void update(int L,int x,int l,int r,int node){
if(l==r){
if(x==1)s[node].sum=L;
if(x==0)s[node].sum=0;
s[node].num=x;
return;
}
int mid=(l+r)>>1;
if(L<=mid)update(L,x,l,mid,node<<1);
else update(L,x,mid+1,r,node<<1|1);
pushup(node);
}
Node query(int L,int R,int l,int r,int node){
if(l>=L && r<=R)return s[node];
int mid=(l+r)>>1;
Node res;res.num=0;res.sum=0;
if(L<=mid) res=cmp(res,query(L,R,l,mid,node<<1));
if(R>mid) res=cmp(res,query(L,R,mid+1,r,node<<1|1));
return res;
}
char t[maxn];
int n,m,cnt;
ll ans,sum;
int main(){
scanf("%d",&n);
scanf("%s",&t);
scanf("%d",&m);
for(int i=0;i<n;i++){
if(t[i]=='0')continue;
sum=(sum+1ll*i)%mod;
cnt++;
q.push(i);
a[i+1].pos=1;
a[i+1].val=i+1;
}
while(!q.empty()){
int k=q.top();q.pop();
sum-=k*1ll;
cnt--;
ans=(ans+1ll*cnt*k-sum)%mod;
}
build(1,n,1);
printf("%lld\n",ans);
while(m--){
int opt,pos;
scanf("%d%d",&opt,&pos);
if(opt==1){
update(pos,1,1,n,1);
Node k1,k2;
k1.sum=0ll,k1.num=0;
k2.sum=0ll,k2.num=0;
if(pos>1)k1=query(1,pos-1,1,n,1);
if(pos<n)k2=query(pos+1,n,1,n,1);
ans=(ans+1ll*pos*k1.num%mod-k1.sum%mod+k2.sum%mod-1ll*pos*k2.num%mod+2*mod)%mod;
}
else {
update(pos,0,1,n,1);
Node k1,k2;
k1.sum=0ll,k1.num=0;
k2.sum=0ll,k2.num=0;
if(pos>1) k1=query(1,pos-1,1,n,1);
if(pos<n) k2=query(pos+1,n,1,n,1);
ans=(ans-1ll*pos*k1.num%mod+k1.sum%mod-k2.sum%mod+1ll*pos*k2.num%mod+2*mod)%mod;
}
printf("%lld\n",ans);
}
return 0;
}
I-牛牛的漢諾塔
題意:漢諾塔,問A柱到B柱,A柱到C柱,B柱到A柱,B柱到C柱,C柱到A柱,C柱到B柱,以及總共會移動多少次。
題解:拿暴力程序打一下表,可以輕鬆的地發現總和次數爲,A->B和B->C滿足一個規律,B->A和C->B滿足一個規律,A->C和C->A分別是個規律,打表出來去OEIS上翻一翻就過了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
ll a,b,c,d,e,f,sum;
ll quick(ll a,ll b){
ll res=1;
while(b){
if(b&1)res=res*a;
a=a*a;
b>>=1;
}
return res;
}
int n;
int main(){
scanf("%d",&n);
sum=quick(2,n)-1;
if(n==1)b=1;
if(n>1){
ll t=n/2-1;
a=3*t+1;
a=(a+quick(2,2*t+3))/9;
d=a;
}
if(n>2){
ll t=(n-1)/2;
for(int i=1;i<=t;i++)
c=4*f+i,f=c;
f=c;
}
if(n>3){
ll t=(n-2)/2;
e=2*(quick(4,t+1)-3*t-4)/9;
}
b=sum-a-c-d-e-f;
printf("A->B:%lld\n",a);
printf("A->C:%lld\n",b);
printf("B->A:%lld\n",c);
printf("B->C:%lld\n",d);
printf("C->A:%lld\n",e);
printf("C->B:%lld\n",f);
printf("SUM:%lld\n",sum);
return 0;
}
eg:剩下B題構造,E題數位dp,J題最短路明天補!