(一道sb题卡了我40min,成功GG)
A:
送分题。sry说他没看懂所以先开D然后成功吊打我,看来Div2不能顺着开题。。
#include<bits/stdc++.h> #define maxn 100005 #define maxm 500005 #define inf 0x7fffffff #define ll long long using namespace std; inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } int main(){ int t=read(); while(t--){ int a=read(),b=read(),c=read(),d=read(),k=read(); int t1=a/c+(a%c?1:0),t2=b/d+(b%d?1:0); if(t1+t2<=k) cout<<t1<<" "<<t2<<endl; else cout<<-1<<endl; } return 0; }
B:
送分题。
#include<bits/stdc++.h> #define maxn 1005 #define maxm 500005 #define inf 0x7fffffff #define ll long long using namespace std; char str[maxn]; inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } int main(){ int T=read(); while(T--){ int n=read(); cin>>str+1; int l=0,r=0,ans=n,flag=0; for(int i=1;i<=n;i++){ if(str[i]=='1' && !flag) l=i,flag=1; if(str[i]=='1') ans=max(ans,max(i*2,(n-i+1)*2)); } for(int i=n;i>=1;i--) if(str[i]==1) {r=i;break;} if(!l) cout<<ans<<endl; else if(l==r) cout<<ans<<endl; else cout<<max(ans,(r-l+1)*2+max(l-1,n-r))<<endl; } return 0; }
C:
回收开头。
题意简洁明了,求方程$ax+by=c$的一组正整数解,满足$x+y\leq n$
数据范围$n\leq 10^{12},c\leq 10^{17},b<a\leq 10^{5}$
花了10min写了一个exgcd,然后wa on 5。当时我就自闭了。
注意到exgcd求出答案后要乘$\frac{c}{gcd(a,b)}$,而这个会爆long long,cf又好像不支持__int128。
换一种思路,能不能求一个x使得$ax\equiv c(mod b)$呢?
容易发现(根据剩余系相关知识),至多枚举b个x就会出现0。
如果我们将x从大往小枚举,那么当第一次出现一个x满足题意时,这个答案一定是a最多且b最少的。
此时由于$a>b$,那么$(x+y)$的值一定是最小的。(用大物品和小物品装背包,大物品个数较多时总个数一定较少)
(这题堪称经典sb题,看到题解就知道自己应该退役了。)
#include<bits/stdc++.h> #define maxn 100005 #define maxm 500005 #define inf 0x7fffffff #define ll long long using namespace std; inline ll read(){ ll x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } int main(){ ll n=read(),p=read(),a=read(),b=read(),x=p/a,T=maxn; while(T--){ if((p-x*a)%b==0){ if(x<0 || x+(p-x*a)/b>n){cout<<-1<<endl;return 0;} else{cout<<x<<" "<<(p-x*a)/b<<" "<<n-(x+(p-x*a)/b)<<endl;return 0;} } x--; } cout<<-1<<endl; return 0; }
D:
送分题,注意到只有一条链满足题意就完事了。
(那么div2开题应该从D开始开?)
#include<bits/stdc++.h> #define maxn 100005 #define maxm 500005 #define inf 0x7fffffff #define ll long long using namespace std; int N,hd[maxn],to[maxn<<1],nxt[maxn<<1],cnt,siz[maxn],deg[maxn]; ll cst[3][maxn],dp[maxn][3][3]; int from[maxn][3][3][2],cl[maxn]; inline ll read(){ ll x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline void addedge(ll u,ll v){ to[++cnt]=v,nxt[cnt]=hd[u],hd[u]=cnt; } inline void dfs(int u,int fa){ int son=0; //cout<<u<<":"<<fa<<endl; for(int i=hd[u];i;i=nxt[i]) if(to[i]!=fa) son=to[i],dfs(son,u); //cout<<son<<endl; if(!son){ for(int i=0;i<3;i++) dp[u][i][i]=cst[i][u]; return; } for(int i=0;i<3;i++) for(int j=0;j<3;j++) for(int k=0;k<3;k++) if(dp[u][i][j]>dp[son][j][k]+cst[i][u] && i!=j && i!=k) dp[u][i][j]=dp[son][j][k]+cst[i][u],from[u][i][j][0]=j,from[u][i][j][1]=k; return; } inline void find(int u,int fa,int x,int y){ cl[u]=x; int son=0; for(int i=hd[u];i;i=nxt[i]) if(to[i]!=fa) son=to[i]; if(son) find(son,u,from[u][x][y][0],from[u][x][y][1]); return; } int main(){ memset(dp,127,sizeof(dp)); N=read(); for(ll k=0;k<3;k++) for(ll i=1;i<=N;i++) cst[k][i]=read(); for(ll i=1;i<=N-1;i++){ ll u=read(),v=read(); addedge(u,v),addedge(v,u); deg[u]++,deg[v]++; } bool flag=0; ll num=0,rt=0; for(ll i=1;i<=N;i++){ if(deg[i]>=3){flag=1;break;} if(deg[i]==1) rt=i; } if(flag) cout<<-1<<endl; else{ dfs(rt,0); ll ans=(1ll<<62),r1=0,r2=0; for(int i=0;i<3;i++) for(int j=0;j<3;j++) if(dp[rt][i][j]<ans) ans=dp[rt][i][j],r1=i,r2=j; find(rt,0,r1,r2); cout<<ans<<endl; for(int i=1;i<=N;i++) cout<<cl[i]+1<<" "; cout<<endl; } return 0; }
E:
送分题,枚举最大值取哪个点后二分最小值求答案。
由于开题顺序错误所以看到这题的时候还有大概5分钟。
秒出做法然而并没有什么软用。
明天补后面的题,先开一把吃鸡。