先总结:
个人方面:审题不清,代码不稳。套路题过不掉。GG
比赛环境方面,判题慢到死,简直没法玩,做的最累的一套水题,如果能及时返回结果,对个人做题心态,感觉都会有提升的.
————————————————————————————————————————————
首先考虑对于假如一只老虎只有两个耳朵或一个尾巴 ,那么总老虎数就是a/2+b,但是一共只有c/4个老虎,那么多出来的就是正常老虎的个数。即a/2+b-c/4
int main(){
int _,a,b,c;
scanf("%d",&_);
while(_--){
scanf("%d%d%d",&a,&b,&c);
a/=2;c/=4;
printf("%d\n",a+b-c);
}
return 0;
}
————————————————————————————————————————————
比赛的时候理解错了题,以为是每轮两个人都走一格,然后看不懂样例,
目测就是两点的曼哈顿距离和N比较下,
如果两个人不能相遇 ,则 -1
能相遇 那么 结果就是1or2 讨论一下就好
瞎猜的 没写代码 。。 等重现,,,
——————————————update————————————————
事实就是这样
考虑一个点能不能走到另一个点
如果能走到
—如果距离是奇数
——如果n是奇数 那么先手多2
——如果n是偶数 那么平
—如果距离是偶数
——如果n是奇数 先手多1
——如果n是偶数 后手多1
不能走到
—如果n是奇数 先手多1
—如果n是偶数 平
#include
using namespace std;
typedef long long int LL;
#define lowbit(x) (x&-x)
#define abs(x) ((x)>0?(x):-(x))
int main(){
int _,n,x1,y1,x2,y2;
scanf("%d",&_);
while(_--){
scanf("%d%d%d%d%d",&n,&x1,&y1,&x2,&y2);
int dis = abs(x1-x2)+abs(y1-y2);
// printf("%d <--- \n",dis);
if((n+1)/2>=dis){
if(dis&1) {
if(n&1) puts("2");
else puts("-1");
}
else {
puts("1");
}
}
else {
if(n&1) puts("1");
else puts("-1");
}
}
return 0;
}
————————————————————————————————————————————
出烂了的题目,
f[i]=f[i-1]+f[i-2]+f[i-3];
代表转移个过程,
int f[200];
int main(){
f[0]=1,f[1]=1,f[2]=2,f[3]=4;
for(int i=4;i<=22;i++){
f[i]=f[i-1]+f[i-2]+f[i-3];
f[i]%=10007;
}
int _,n,x;
scanf("%d",&_);
while(_--){
scanf("%d",&n);
int ans = 1;
for(int i=1;i"%d",&x);
ans*=f[x];
ans%=10007;
}
printf("%d\n",ans);
}
return 0;
}
————————————————————————————————————————————
这个明白题意就能AC了
int main(){
int _,a,b,c;
scanf("%d",&_);
while(_--){
scanf("%d%d%d",&a,&b,&c);
printf("%d\n",a*b+(a/30)*c);
}
return 0;
}
————————————————————————————————————————————
其实这题贪心就好,
我们要最少的水杯,那就倍增的将若干个杯子变成一个就好了,
那么也就是说2x最后都能变成一个水杯, 这是不花费是最少的杯子个数
而我们要是最后的杯子个数<=k
那么只要最贪心的这个最小的两个2x 变成一个就好了,
那么就是不断的加上最小的一个2x,最后能将这两个凑成一个
暴力写就好了 时间上不会超过\logn的.
(其实就是一个树状数组更新的过程么。。
#define lowbit(x) (x&-x)
int a[N];
int cal(LL a){
int num = 0;
while(a){
if(a&1) num++;
a>>=1;
}
return num;
}
int main(){
int _,k;
LL n;
scanf("%d",&_);
while(_--){
scanf("%lld",&n);
scanf("%d",&k);
LL ans = 0;
while(cal(n)>k){
ans+=lowbit(n);
n+=lowbit(n);
}
printf("%lld\n",ans);
}
return 0;
}
————————————————————————————————————————————
这题只知道要对树进行剖分,但是对于链上能不能构成三角形,我实在没有想到一个合适的复杂度来处理,
最后在他人的提示下才知道怎么处理,
先反过来想,一个序列里的数不能构成三角形,那么是fibo数列,没有问题,(详见2016CCPC长春签到题)
那么在109的范围内fibo的长度也不超过50
那么也就是说如果数列的长度大于50 那么一定可以构成三角形,
所以对于大数据我们这样处理就好, 小数据就可以O(50)处理就好了
个人用的是树剖,将边权转化为点权,
S->T路径上的所有点权处理一下就行了
(注意要去掉LCA(S,T)的点权
后来知道这是一个陈题,赛后在别处AC了一发
#include
#define abs(x) ((x)>0?(x):-(x))
typedef long long int LL ;
using namespace std;
const int N = 100000+7;
const int MOD = 1000000007;
/*******************************************************/
int n,m;
int c[N];
vectorint ,int> >G[N];
void add(int u,int v,int w){
G[u].push_back(make_pair(v,w));
G[v].push_back(make_pair(u,w));
}
int fa[N],dep[N],sz[N],son[N];
void dfs1(int u,int f,int d){
fa[u]=f,dep[u]=d,sz[u]=1,son[u]=0;
int gz=G[u].size();
for(int i=0,to;iif(to==f) continue;
c[to]=G[u][i].second;
dfs1(to,u,d+1);
sz[u]+=sz[to];
if(sz[son[u]]int top[N],tree[N],pre[N],cnt;
void dfs2(int u,int tp){
top[u]=tp,tree[u]=++cnt,pre[tree[u]]=u;
if(son[u])dfs2(son[u],tp);
int gz=G[u].size();
for(int i=0,to;iif(to==fa[u]||to==son[u]) continue;
dfs2(to,to);
}
}
int b[100];
void solve2(int x,int y,int lca){
int fx=top[x],fy=top[y];
int tot=0;
while(fx!=fy){
if(dep[fx]// printf("%d %d <-----\n",x,fx);
for(int i=tree[x];i>=tree[fx];i--){
// printf("%d<-\n",i);
if(pre[i]==lca) continue;
b[tot++]=c[pre[i]];
}
x=fa[fx],fx=top[x];
}
if(dep[x]for(int i=tree[x];i>=tree[y];i--){
if(pre[i]==lca) continue;
b[tot++]=c[pre[i]];
}
sort(b,b+tot);
// for(int i=0;i
for(int i=2;iif (b[i-1]+b[i-2]>b[i]){
puts("Yes");
return ;
}
}
puts("No");
return ;
}
void solve(int x,int y){
int u=x,v=y;
int fx=top[x],fy=top[y];
int tot=0;
while(fx!=fy){
if(dep[fx]abs(tree[x]-tree[fx])+1;
x=fa[fx],fx=top[x];
}
if(dep[x]abs(tree[x]-tree[y]);
if(tot>=60) puts("Yes");
else solve2(u,v,y);
return ;
}
void init(){
cnt = 0;c[1]=0;
for(int i=1;i<=n;i++) G[i].clear();
}
int main(){
int _;
// scanf("%d",&_);
while(~scanf("%d",&n)){
init();
for(int i=2,u,v,w;i<=n;i++){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
dfs1(1,0,1);fa[1]=1;
dfs2(1,1);
// for(int i=1;i<=n;i++) printf("%d ",tree[i]);puts("");
scanf("%d",&m);
int u,v;
while(m--){
scanf("%d%d",&u,&v);
solve(u,v);
}
}
return 0;
}
————————————————————————————————————————————
这道题最开始以为是一个数位dp,想在求区间回文数个数的代码上改一改 ,但是因为渣渣实在太菜,没有调出来,
快结束暴力处理了一下范围内所有等凹数字,发现只有180k+,
那么我们只要对区间进行二分就好了.
注:这题只是意念AC,等重现赛在提交一下 (已经AC)
后来看题解说数位DP也能过 等下课回来补一个
(数位dp做法已更新 在下面)
#include
using namespace std;
typedef long long int LL;
LL sum;
LL a[500000],cnt;
int num[20],len;
void solve1(int n){
if(n<10) return ;
LL tem = n;len =0 ;
num[len++]=n%10;
n/=10;
while(n){
num[len++]=n%10;
tem=tem*10+n%10;
n/=10;
}
if(num[0]!=num[len-1])
a[++cnt]=tem;
}
void solve2(int n){
if(n<10) return ;
LL tem = n;len = 0;
while(n){
num[len++]=n%10;
tem=tem*10+n%10;
n/=10;
}
if(num[0]!=num[len-1])
a[++cnt]=tem;
}
void dfs(int s,int pre,int l,int n,bool state){
if(s>=l) {
if(state){
solve1(n);
solve2(n);
}
return ;
}
for(int i=pre;i>=0;i--){
dfs(s+1,i,l,n*10+i,istate);
}
}
LL cal(LL n){
int l =1,r=cnt,mid,ans;
while(l<=r){
mid = (l+r)>>1;
if(a[mid]>n) {
r=mid-1;
}
else l=mid+1;
}
return r;
}
int main(){
cnt = 0;
for(int i=2;i<=9;i++)
dfs(0,9,i,0,0);
// printf("\n%lld\n",cnt);
sort(a+1,a+cnt+1);
// for(int i=1;i<=cnt;i++){
// if(a[i]<=100000) sum++;
// else break;
// printf("%lld,",a[i]);
// }
// printf("%d\n",sum);
int _,k;
LL n,a,b;
scanf("%d",&_);
while(_--){
scanf("%lld%lld",&a,&b);
printf("%lld\n",cal(b)-cal(a-1));
}
return 0;
}
————–Update————–
数位dp是可解的
在基础的求回文数的数位dp上面多开两个维度,记录最高位的数字和前一位的数字即可
dp[最高位][当前位][前一位的数字][最高位的数字][可不可行(其实可以去掉这一维)]
dfs(最高位,当前位,前一位的数字,最高位的数字,数位限制,可不可行)
转移的时候 只要考虑等凹数字的性质搜下去就行了 对于不满足的 可以不用搜
最开始并没有想到要记录最高位的数字 这时候不记忆化 也能能AC(因为数据水 没有卡t)
最后在Dei.的提示下 才写对 鸣谢
#include
using namespace std;
typedef long long int LL;
int num[20],temp[20],len;
LL dp[20][20][10][10][2];
LL dfs(int pos,int cur,int pre,int fir,bool limit,bool state){
if(cur<0) return state&&(pos>=2);
if(!limit&&dp[pos][cur][pre][fir][state]!=-1)
return dp[pos][cur][pre][fir][state];
int endi = 9;
if(limit) endi = num[cur];
LL res = 0;
for(int i=0;i<=endi;i++){
temp[cur]=i;
if(pos==cur&&0==i){
res+=dfs(pos-1,cur-1,i,0,limit&&(i==endi),state);
}
else if(state&&cur<(pos+1)/2){
if(temp[pos-cur]==i)
res+=dfs(pos,cur-1,i,fir,limit&&(i==endi),temp[pos-cur]==i);
}
else if(state){
if(pos!=cur&&i>pre) continue;
if(i==temp[pos]&&cur==(pos+1)/2) continue;
res+=dfs(pos,cur-1,i,temp[pos],limit&&(i==endi),state);
}
}
if(!limit) dp[pos][cur][pre][fir][state]=res;
return res;
}
LL solve(LL n){
len = 0;
while(n){
num[len++]=n%10;
n/=10;
}
return dfs(len-1,len-1,0,0,1,1);
}
int main(){
memset(dp,-1,sizeof(dp));
int _;
LL l,r;
scanf("%d",&_);
while(_--){
scanf("%lld%lld",&l,&r);
printf("%lld\n",solve(r)-solve(l-1));
}
return 0;
}
————————————————————————————————————————————
这道题被 Pending Rejudging了 但绝对能AC
51nod上有一个加强版的题目 题号1821
就是先升序排一下,在维护一个从0开始的变量,如果ans+1>=a[i]
的话就说明[0,ans+a[i]]元素都能凑出来
处理一下就好了
int a[N];
int main(){
int _,n;
scanf("%d",&_);
while(_--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+n+1);
LL ans = 0;
for(int i=1;i<=n;i++){
if(ans+1>=a[i]) ans+=a[i];
else break;
}
printf("%lld\n",ans);
}
return 0;
}