ZROI 欢度新春娱乐赛
WOW!
T1:
十分easy?
考场上预处理+gcd
大致思路是一个点x-1和y-1互质,那么这个点一定看得见1
70分,原因是要从1枚举到1001才行,因为(如题
源代码
#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int T;
int c[N][N]={0};
int f[N][N]={0};
int g[N][N]={0};
int gcd(int x,int y){
if(x==0) return y;
else return gcd(y%x,x);
}
int can(int x,int y){
if(x==0&&y==0) return 1;
if(x==0||y==0){
if(x+y==1) return 1;
else return 0;
}
if(gcd(x,y)!=1) return 0;
return 1;
}
void sol(){
for(int i=1;i<=1000;i++){
for(int j=1;j<=1000;j++){
c[i][j]=can(i-1,j-1);
}
}
for(int i=1;i<=1000;i++){
for(int j=1;j<=1000;j++){
f[i][j]=f[i][j-1]+c[i][j];
}
}
for(int i=1;i<=1000;i++){
for(int j=1;j<=1000;j++){
g[i][j]=g[i-1][j]+f[i][j];
}
}
}
void Debug(){
for(int i=1;i<=10;i++){
for(int j=1;j<=10;j++){
cout << c[i][j] << " ";
}
cout << endl;
}
}
int main(){
//ios::sync_with_stdio(false);
sol();
//Debug();
scanf("%d",&T);
while(T--){
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",g[x+1][y+1]);
}
return 0;
}
订正代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int T;
int c[N][N]={0};
int f[N][N]={0};
int g[N][N]={0};
int gcd(int x,int y){
if(x==0) return y;
else return gcd(y%x,x);
}
int can(int x,int y){
if(x==0&&y==0) return 1;
if(x==0||y==0){
if(x+y==1) return 1;
else return 0;
}
if(gcd(x,y)!=1) return 0;
return 1;
}
void sol(){
for(int i=1;i<=1001;i++){
for(int j=1;j<=1001;j++){
c[i][j]=can(i-1,j-1);
}
}
for(int i=1;i<=1001;i++){
for(int j=1;j<=1001;j++){
f[i][j]=f[i][j-1]+c[i][j];
}
}
for(int i=1;i<=1001;i++){
for(int j=1;j<=1001;j++){
g[i][j]=g[i-1][j]+f[i][j];
}
}
}
void Debug(){
for(int i=1;i<=1001;i++){
for(int j=1;j<=1001;j++){
}
}
}
int main(){
//ios::sync_with_stdio(false);
sol();
//Debug();
scanf("%d",&T);
while(T--){
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",g[x+1][y+1]);
}
return 0;
}
T2:
hard!
考场上想到了暴力DFS
源代码:
#include<bits/stdc++.h>
using namespace std;
#define p 998244353
const int N=500005;
int n,m;
int hed[N],tal[N],val[N],nxt[N],cnt=0;
map<int,map<int,bool> > s;
int ans=0;
void add(int x,int y){
cnt++;
tal[cnt]=y;
nxt[cnt]=hed[x];
hed[x]=cnt;
}
void zou(int x){
ans++;
ans%=p;
for(int i=hed[x];i;i=nxt[i]){
int y=tal[i];
zou(y);
}
}
int main(){
//ios::sync_with_stdio(false);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
if(s[a][b]==1) continue;
add(a,b);
s[a][b]=1;
}
for(int i=1;i<=n;i++){
zou(i);
}
printf("%d\n",ans);
return 0;
}
30分,听取T声一片
正解:
BFS
想想,什么点的入度为0?
起点
那么…
每次先将入度为0的点入队
每次用队里的点去更新另外点
那么,更新完后入度–
如果一个点入度变成了0,则进队
还有一点:重边要判掉
订正代码:
#include<bits/stdc++.h>
using namespace std;
#define p 998244353
typedef long long ll;
const int N=500005;
int n,m;
ll f[N]={0};
map<ll,bool> s;
int d[N]={0};
int hed[N],tal[N],nxt[N],cnt=0;
int h=1,t=0;
int q[N*10];
ll ans=0;
void add(int x,int y){
cnt++;
tal[cnt]=y;
nxt[cnt]=hed[x];
hed[x]=cnt;
}
int main(){
scanf("%d%d",&n,&m);
while(m--){
int a,b;
scanf("%d%d",&a,&b);
if(s[a*1000000ll+b]==0){
s[a*1000000ll+b]=1;
add(a,b);
d[b]++;
}
}
for(int i=1;i<=n;i++){
f[i]=1;
if(d[i]==0) q[++t]=i;
}
while(h<=t){
int u=q[h];
h++;
for(int i=hed[u];i;i=nxt[i]){
int v=tal[i];
d[v]--;
f[v]+=f[u];
f[v]%=p;
if(d[v]==0) q[++t]=v;
}
}
for(int i=1;i<=n;i++) ans+=f[i],ans%=p;
printf("%lld\n",ans);
return 0;
}
T3:
玄学emm
一开始打了个暴力分块
然后:0!
WHAT?
源代码:
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
const int M=500;
struct node{
int num;
int Rank;
}s[N];
int n,m,Q;
int u=0;
int col[N];
int l[M]={0},r[M]={0};
int LZT[M]={0};
bool cmp(node x,node y){
return x.num<y.num;
}
void doit(int left,int right,int LB,int RB,int NUM){
for(int i=left;i<=right;i++){
if(s[i].Rank>=LB&&s[i].Rank<=RB){
s[i].num+=NUM;
}
}
sort(s+left,s+right+1,cmp);
}
int sec(int left,int right,int LB,int RB,int NUM){
int u=-1;
for(int i=left;i<=right;i++){
if(s[i].Rank>=LB&&s[i].Rank<=RB){
if(s[i].num<=NUM){
u=max(u,s[i].num);
}
}
}
return u;
}
int serch(int left,int right,int LB,int RB,int NUM){
int l=left,r=right,ans=-1;
while(l<=r){
int mid=(l+r)>>1;
if(s[mid].num<=NUM) ans=s[mid].num,l=mid+1;
else r=mid-1;
}
return ans;
}
int main(){
//ios::sync_with_stdio(false);
scanf("%d%d%d",&n,&m,&Q);
u=sqrt(n);
for(int i=1;i<=n;i++) scanf("%d",&col[i]),s[i].Rank=i,s[i].num=col[i];
for(int i=1;i<=u;i++){
l[i]=r[i-1]+1;
r[i]=l[i]+u-1;
}
r[u]=n;
for(int i=1;i<=u;i++){
sort(s+l[i],s+r[i]+1,cmp);
}
while(m--){
int opt;
scanf("%d",&opt);
if(opt==1){
int L,R,X;
scanf("%d%d%d",&L,&R,&X);
for(int i=1;i<=u;i++){
if(r[i]<L) continue;
if(l[i]>R) break;
if(l[i]<=L&&r[i]>=R){
doit(l[i],r[i],L,R,X);
break;
}
if(l[i]<=L&&r[i]>=L){
doit(l[i],r[i],L,R,X);
continue;
}
if(l[i]<=R&&r[i]>=R){
doit(l[i],r[i],L,R,X);
break;
}
LZT[i]+=X;
}
}
else{
int L,R,ans=-1;
scanf("%d%d",&L,&R);
for(int i=1;i<=u;i++){
if(r[i]<L) continue;
if(l[i]>R) break;
int num;
if(l[i]<=L&&r[i]>=R){
num=sec(l[i],r[i],L,R,Q-LZT[i]);
}
else if(l[i]<=L&&r[i]>=L){
num=sec(l[i],r[i],L,R,Q-LZT[i]);
}
else if(l[i]<=R&&r[i]>=R){
num=sec(l[i],r[i],L,R,Q-LZT[i]);
}
else num=serch(l[i],r[i],L,R,Q-LZT[i]);
ans=max(ans,num);
}
printf("%d\n",ans);
}
}
return 0;
}
然后发现add操作失误,再加上一笔卡常技巧就100了。
订正代码:
见这里
T4
大水题
具体思路就是模拟
每次×2最好
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll l,r;
ll ans=0;
int main(){
//ios::sync_with_stdio(false);
scanf("%lld%lld",&l,&r);
while(1){
if(l>r) break;
ans++;
l*=2;
}
printf("%lld\n",ans);
return 0;
}
T5
神题
我想到的是:DFS一遍,打出时间戳,同层贡献分别算+快速幂
20分
订不出来,没人A
#include<bits/stdc++.h>
using namespace std;
#define p 1000000007
typedef long long ll;
const int N=500005;
int n;
int hed[N],tal[N],nxt[N],cnt=0;
int dis[N]={0};
ll cont[N]={0};
int opt=0;
ll ans=0;
ll ck=0;
ll out[N];
int Q[N];
ll P[N];
int Rk=0;
ll qpow(ll x,ll y){
ll sum=1;
while(y){
if(y&1) sum=(sum*x)%p;
x=(x*x)%p;
y>>=1;
}
return sum;
}
void add(int x,int y){
cnt++;
tal[cnt]=y;
nxt[cnt]=hed[x];
hed[x]=cnt;
}
void dfs(int x,int fa){
dis[x]=dis[fa]+1;
cont[dis[x]]++;
P[dis[x]]++;
if(cont[dis[x]]==1){
opt++;
}
for(int i=hed[x];i;i=nxt[i]){
int y=tal[i];
if(y==fa) continue;
dfs(y,x);
}
}
int main(){
//ios::sync_with_stdio(false);
scanf("%d",&n);
for(ll i=1;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
dfs(1,0);
//cout << C(5,3) << endl;
int all=0;
for(int i=1;i<=opt;i++){
all=all+cont[i];
}
for(int i=1;i<=opt;i++){
ans=(ans+(cont[i]*qpow(2,all-cont[i]))%p)%p;
}
printf("%lld\n",ans);
return 0;
}
/*
5
1 2
2 3
1 4
1 5
*/
T6
大模拟
考试时为未注意细节,40
源代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,T,m;
char s;
int main(){
//ios::sync_with_stdio(false);
scanf("%d%d%d%d",&n,&k,&T,&m);
scanf("%c",&s);
if(T-k>1) printf("<< ");
for(int i=max(1,T-k);i<=min(n,T+k);i++){
if(i==T) printf("(%d) ",i);
else printf("%d ",i);
}
if(T+k<n) printf(">>");
printf("\n");
for(int i=1;i<=m;i++){
char c[2005];
int f=0;
while(c[f+1]=getchar(),c[f+1]!='\n') f++;
if(c[7]=='>'){
if(T+k>=n) printf("WARNING\n");
else{
for(int j=max(1,n-k);j<=n;j++){
if(j==max(1,n-k)) printf("<< ");
if(j==n){
printf("(%d)\n",j);
break;
}
printf("%d ",j);
}
T=n;
}
}
else if(c[7]=='<'){
if(T-k<=1) printf("WARNING\n");
else{
for(int j=1;j<=min(n,1+k);j++){
if(j==1){
printf("(%d) ",j);
continue;
}
printf("%d ",j);
if(j==min(n,1+k)){
printf(">>\n");
}
}
T=n;
}
}
else{
int num=c[7]-'0';
for(int j=8;j<=f;j++) num=num*10+c[j]-'0';
if(num<1||num>n) printf("WARNING\n");
else if(num>T+k||num<T-k) printf("WARNING\n");
else{
if(num-k>1) printf("<< ");
for(int i=max(1,num-k);i<=min(n,num+k);i++){
if(i==num) printf("(%d) ",i);
else printf("%d ",i);
}
if(num+k<n) printf(">>");
printf("\n");
T=num;
}
}
}
return 0;
}
后来秒发现问题,立马改正
代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,T,m;
char s;
int main(){
//ios::sync_with_stdio(false);
scanf("%d%d%d%d",&n,&k,&T,&m);
scanf("%c",&s);
if(T-k>1) printf("<< ");
for(int i=max(1,T-k);i<=min(n,T+k);i++){
if(i==T) printf("(%d) ",i);
else printf("%d ",i);
}
if(T+k<n) printf(">>");
printf("\n");
for(int i=1;i<=m;i++){
char c[2005];
int f=0;
while(c[f+1]=getchar(),c[f+1]!='\n') f++;
if(c[7]=='>'){
if(T+k>=n) printf("WARNING\n");
else{
for(int j=max(1,n-k);j<=n;j++){
if(j==max(1,n-k)) printf("<< ");
if(j==n){
printf("(%d)\n",j);
break;
}
printf("%d ",j);
}
T=n;
}
}
else if(c[7]=='<'){
if(T-k<=1) printf("WARNING\n");
else{
for(int j=1;j<=min(n,1+k);j++){
if(j==1){
printf("(%d) ",j);
if(j==min(n,1+k)){
printf(">>\n");
}
continue;
}
printf("%d ",j);
if(j==min(n,1+k)){
printf(">>\n");
}
}
T=1;
}
}
else{
int num=c[7]-'0';
for(int j=8;j<=f;j++) num=num*10+c[j]-'0';
if(num<1||num>n) printf("WARNING\n");
else if(num>T+k||num<T-k) printf("WARNING\n");
else{
if(num-k>1) printf("<< ");
for(int i=max(1,num-k);i<=min(n,num+k);i++){
if(i==num) printf("(%d) ",i);
else printf("%d ",i);
}
if(num+k<n) printf(">>");
printf("\n");
T=num;
}
}
}
return 0;
}
T7
难·DP
好难
有题解来着
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=5005,M=1e9+7;
ll n;
ll a;
ll b;
ll f[N][N];
ll c[N][N];
void work(void)
{
//cout << "***" << endl;
for(int i=0;i<=N;i++) f[i][0]=1;
for(int i=1;i<N;i++)
{
for(int j=1;j<=i&&j<N;j++)
{
f[i][j]=(f[i-1][j-1]+f[i-1][j])%M;
}
}
//cout << "***" << endl;
for(int i=0;i<=N;i++) c[i][i]=1;
//cout << "***" << endl;
for(int i=2;i<N;i++)
{
for(int j=1;j<i&&j<N;j++)
{
c[i][j]=((i-1)*c[i-1][j]%M+c[i-1][j-1])%M;
}
}
//cout << "***" << endl;
}
int main()
{
work();
//cout << "***" << endl;
scanf("%lld%lld%lld",&n,&a,&b);
if(a+b>n+1) printf("0\n");
else printf("%lld\n",f[a+b-2][a-1]*c[n-1][a+b-2]%M);
return 0;
}
T8
两次dijkstra秒出答案
记得加堆优化
代码
T9
BFS
加上优先队列优化
源代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2005;
int n,m;
char s[N][N];
int f[N][N];
struct ma
{
int x;
int y;
};
bool operator <(const ma &a,const ma &b)
{
return f[a.x][a.y]>f[b.x][b.y];
}
priority_queue<ma> q;
void push(int x,int y)
{
ma a;
a.x=x;
a.y=y;
q.push(a);
}
int main()
{
memset(f,-1,sizeof(f));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%s",s[i]+1);//%%%gaolinxiang dalao 的快读快写貌似一行足矣
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(s[i][j]=='+')
{
f[i][j]=0;
push(i,j);
}
}
}
while(!q.empty())
{
ma u=q.top();
int x=u.x;
int y=u.y;
int z=f[x][y];
q.pop();
//向四个方向拓展
x=u.x,y=u.y;
while(x<n&&s[x+1][y]=='.')
{
x++;
if(z+1<f[x][y]||f[x][y]==-1){
f[x][y]=z+1;
push(x,y);
}
}
x=u.x,y=u.y;
while(x>1&&s[x-1][y]=='.')
{
x--;
if(z+1<f[x][y]||f[x][y]==-1){
f[x][y]=z+1;
push(x,y);
}
}
x=u.x,y=u.y;
while(y<n&&s[x][y+1]=='.')
{
y++;
if(z+1<f[x][y]||f[x][y]==-1){
f[x][y]=z+1;
push(x,y);
}
}
x=u.x,y=u.y;
while(y>1&&s[x][y-1]=='.')
{
y--;
if(z+1<f[x][y]||f[x][y]==-1){
f[x][y]=z+1;
push(x,y);
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<m;j++)
{
if(s[i][j]=='#') printf("# ");
else if(f[i][j]==-1) printf("X ");
else printf("%d ",f[i][j]);
}
if(s[i][m]=='#') printf("#");
else if(f[i][m]==-1) printf("X");
else printf("%d",f[i][m]);
printf("\n");
}
return 0;
}
T10
数论5合1
想看正解的:点这里
我只会30分暴力+40分特判
源代码:
#include<bits/stdc++.h>
using namespace std;
#define p 999911659
typedef long long ll;
int n,m,k;
bool g[1005][1005]={0};
ll f[1005][1005]={0};
ll qpow(ll x,ll y){
ll ans=1;
while(y){
if(y&1) ans=(ans*x)%p;
x=(x*x)%p;
y>>=1;
}
return ans;
}
void Subtask1(){
scanf("%d",&k);
while(k--){
int l,r;
scanf("%d%d",&l,&r);
g[++l][++r]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(i>j) g[i][j]=1;
}
}
for(int i=1;i<=m;i++) if(!g[1][i]) f[1][i]=1;
for(int i=1;i<=n;i++) if(!g[i][1]) f[i][1]=1;
for(int i=2;i<=n;i++){
for(int j=2;j<=m;j++){
if(g[i][j]) continue;
f[i][j]=(f[i-1][j]+f[i][j-1])%(p-1);
}
}
printf("%lld\n",qpow(1ll*233,f[n][m]));
}
int main(){
//ios::sync_with_stdio(false);
scanf("%d%d",&n,&m);
if(n<=1000&&m<=1000){
Subtask1();
}
else{
printf("1\n");
return 0;
}
return 0;
}
T11
不说了