-
OI-Contest 荣耀徽章
该用户太菜了,一个徽章也没有 (´・ω・`) -
个人简介
/* 30分: 某种神秘的暴力
60分: 枚举两个班各分多少糖果,判断是否符合要求
100分: 推公式 显然n%(x+y)==0时成立 假设一班小朋友每人a颗糖果,二班小朋友每人a+1颗糖果 a*x+(a+1)y=n a(x+y)+y=n n%(x+y)==y 同理得n%(x+y)==x */ #include<bits/stdc++.h> using namespace std; int main(){ freopen("candy.in","r",stdin); freopen("candy.out","w",stdout); int t; scanf("%d",&t); while(t--){ int n,x,y; scanf("%d%d%d",&n,&x,&y); if(n%(x+y)==0){ printf("Yes\n"); continue; } if(n%(x+y)==x){ printf("Yes\n"); continue; } if(n%(x+y)==y){ printf("Yes\n"); continue; } printf("No\n"); } return 0; }
/* 30分: 暴搜
60分: 二进制枚举
100分: 从小到大选数 注意到8+5=13 重要性质:若x在集合B中,x+13也可以在集合B中 证明: x在集合B中,则x+5和x+8一定不在集合B中 因此x+13能在集合B中
把数分为每13个一组 暴搜n小于等于13的情况 并处理n=13时,前k(k<13)个数里能选几个 输出n/13*ans[13]+c[n%13] */ #include<bits/stdc++.h> using namespace std; int pan[20],c[20],ans[20]; void dfs(int depth,int num){ if(depth>ans[num]){ ans[num]=depth; if(num==13){ for(int i=1;i<=num;i++){ if(pan[i]) c[i]=1; else c[i]=0; c[i]+=c[i-1]; } } } for(int i=1;i<=num;i++){ if(pan[i]==0){ if(i-5>0&&pan[i-5]==1) continue; if(i+5<=13&&pan[i+5]==1) continue; if(i-8>0&&pan[i-8]==1) continue; if(i+8<=13&&pan[i+8]==1) continue; pan[i]=1; dfs(depth+1,num); pan[i]=0; } } return ; }
int main(){ freopen("set.in","r",stdin); freopen("set.out","w",stdout); for(int i=1;i<=13;i++) dfs(0,i); int t; scanf("%d",&t); while(t--){ int n; scanf("%d",&n); if(n<=13) printf("%d\n",ans[n]); else printf("%d\n",n/13*ans[13]+c[n%13]); } return 0; }
/* 30分: 暴搜拿不到,需要二进制枚举
60分: 某种神秘的O(n^4)做法
100分: 区间DP dp[i][j]表示把[i,j]这个区间的狼全打败所承受的最小伤害 枚举中间点k,dp[i][j]=min(dp[i][k-1]+dp[k+1][j]+a[k]+b[i-1]+b[j+1]) 注意每组数据结束后要清空ab数组 */ #include<bits/stdc++.h> using namespace std; const int N=210; const int inf=1e9+7; int a[N],b[N],dp[N][N]; int main(){ freopen("wolf.in","r",stdin); freopen("wolf.out","w",stdout); int t; scanf("%d",&t); for(int u=1;u<=t;u++){ int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) dp[i][j]=inf; for(int len=1;len<=n;len++){ for(int i=1;i+len-1<=n;i++){ int j=i+len-1; for(int k=i;k<=j;k++){ dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]+a[k]+b[i-1]+b[j+1]); //b[n+1] } } } printf("Case #%d: %d\n",u,dp[1][n]); for(int i=1;i<=n;i++){ a[i]=0; b[i]=0; } } return 0;
}
/* 30分: 暴搜
60分: 某种神秘的特殊情况
100分: 考虑为何会出现多种方案 在记录一个数x时,可以选择删掉x左边的数,也可以删掉x右边的数 什么时候可以删掉左边的数? 按顺序记录数时,一个数只要被记录到b中,就没有用了 因此,左边的数没有出现在b中,或者左边的数在b中的顺序在x之前 此时可以删掉左边的数 右边的数同理 在a中记录b的数的出现顺序即可
左右均可删,答案*2 左右一可删,答案不变 左右不可删,答案为0 / #include<bits/stdc++.h> using namespace std; const int N=200010; const int mod=998244353; const int inf=1e9+7; int a[N],b[N],num[N],pos[N]; int main(){ freopen("operation.in","r",stdin); freopen("operation.out","w",stdout); int t; scanf("%d",&t); while(t--){ int n,k; scanf("%d%d",&n,&k); num[0]=inf; num[n+1]=inf; for(int i=1;i<=n;i++){ num[i]=0; pos[i]=0; } for(int i=1;i<=n;i++){ scanf("%d",&a[i]); pos[a[i]]=i; } for(int i=1;i<=k;i++){ scanf("%d",&b[i]); num[pos[b[i]]]=i; } int ans=1; for(int i=1;i<=k;i++){ if(num[pos[b[i]]-1]>num[pos[b[i]]]&&num[pos[b[i]]+1]>num[pos[b[i]]]){ ans=0; } if(num[pos[b[i]]-1]<num[pos[b[i]]]&&num[pos[b[i]]+1]<num[pos[b[i]]]){ ans=2; ans%=mod; } } printf("%d\n",ans); } return 0; }
-
证书
该用户太菜了,一本证书也没有 (´・ω・`) -
AC题目
Problem Tags
- 动态规划
- 9
- 二分
- 8
- 贪心
- 6
- 前缀和
- 5
- gcd
- 5
- 计算
- 5
- 树
- 5
- 数学
- 5
- 其他
- 4
- dfs
- 4
- 模拟
- 4
- 快速幂
- 4
- 差分
- 4
- DFS枚举
- 4
- 排序
- 3
- map
- 3
- 递归
- 3
- 组合数学
- 3
- 双指针
- 3
- 栈
- 3