Codeforces Round #528 (Div. 1, based on Technocup 2019 Elimination Round 4) 自閉記
阿新 • • 發佈:2018-12-24
整天自閉。
A:有各種討論方式。我按橫座標排了下然後討論了下縱座標單調和不單調兩種情況。寫了15min也就算了,誰能告訴我printf和cout輸出不一樣是咋回事啊?又調了10min啊?
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #defineView Codeint long long char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n; struct data { int x,y; bool operator <(const data&a) const { return x<a.x||x==a.x&&y<a.y; } bool operator ==(const data&a) const {return x==a.x&&y==a.y; } }a[3],ans[1000000]; signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); const char LL[]="%I64d\n"; #endif for (int i=0;i<3;i++) a[i].x=read(),a[i].y=read(); sort(a,a+3); if (a[0].y<=a[1].y==a[1].y<=a[2].y) { for (int i=min(a[0].y,a[1].y);i<=max(a[0].y,a[1].y);i++) ans[++n].x=a[0].x,ans[n].y=i; for (int i=a[0].x;i<=a[1].x;i++) ans[++n].x=i,ans[n].y=a[1].y; for (int i=min(a[1].y,a[2].y);i<=max(a[1].y,a[2].y);i++) ans[++n].x=a[1].x,ans[n].y=i; for (int i=a[1].x;i<=a[2].x;i++) ans[++n].x=i,ans[n].y=a[2].y; } else { for (int i=a[0].x;i<=a[1].x;i++) ans[++n].x=i,ans[n].y=a[0].y; for (int i=min(a[1].y,a[0].y);i<=max(a[1].y,a[0].y);i++) ans[++n].x=a[1].x,ans[n].y=i; for (int i=min(a[0].y,a[2].y);i<=max(a[0].y,a[2].y);i++) ans[++n].x=a[1].x,ans[n].y=i; for (int i=a[1].x;i<=a[2].x;i++) ans[++n].x=i,ans[n].y=a[2].y; } sort(ans+1,ans+n+1); n=unique(ans+1,ans+n+1)-ans-1; cout<<n<<endl; for (int i=1;i<=n;i++) cout<<ans[i].x<<' '<<ans[i].y<<endl; return 0; }
B:將權值平均分在葉節點的邊上即可。感性證明。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define int long long #define N 100010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,p[N],t,degree[N]; struct data{int to,nxt; }edge[N<<1]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); const char LL[]="%I64d\n"; #endif n=read(),m=read(); for (int i=1;i<n;i++) { int x=read(),y=read(); degree[x]++,degree[y]++; } if (n==2) {cout<<m;return 0;} int cnt=0; for (int i=1;i<=n;i++) if (degree[i]==1) cnt++; printf("%.8f",m*2.0/cnt); return 0; }View Code
這個時候就40min了,簡直墊底。
C:考慮讓置換後的串在不超過上界的前提下儘量大。一旦某一位不卡上界了,後面就只需要貪心地儘量滿足下界。於是在每種字元第一次出現的位置考慮卡與不卡兩種情況即可。簡直是個思博題。但它是個碼農題。不明白意義何在。寫的醜的沒邊了。調了30min,最後3min過非常刺激。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define int long long #define N 1000010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int T,n,k,a[N],b[N],c[N],match[27],tmp[27]; char s[N]; bool used[27]; signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); const char LL[]="%I64d\n"; #endif T=read(); while (T--) { k=read(); scanf("%s",s+1);n=strlen(s+1); for (int i=1;i<=n;i++) a[i]=s[i]-'a'+1; scanf("%s",s+1); for (int i=1;i<=n;i++) b[i]=s[i]-'a'+1; scanf("%s",s+1); for (int i=1;i<=n;i++) c[i]=s[i]-'a'+1; memset(match,0,sizeof(match));memset(used,0,sizeof(used)); bool flag=0; for (int i=1;i<=n;i++) { if (!match[a[i]]) { for (int x=c[i]-1;x>=1;x--) if (!used[x]) { for (int j=1;j<=k;j++) tmp[j]=match[j]; match[a[i]]=x;used[x]=1; bool islim=1;flag=1; for (int j=1;j<=n;j++) { if (match[a[j]]&&match[a[j]]>b[j]) islim=0; if (islim&&match[a[j]]&&match[a[j]]<b[j]) {flag=0;break;} if (!match[a[j]]) { if (!islim) { for (int x=k;x>=1;x--) if (!used[x]) {match[a[j]]=x,used[x]=1;break;} } else { bool f=1; for (int x=k;x>=1;x--) if (!used[x]) { if (x<b[j]) f=0; else match[a[j]]=x,used[x]=1,islim=x==b[j]; break; } if (!f) {flag=0;break;} } } } if (flag) break; memset(used,0,sizeof(used)); for (int j=1;j<=k;j++) { match[j]=tmp[j]; if (match[j]) used[match[j]]=1; } break; } if (flag) break; if (!used[c[i]]) match[a[i]]=c[i],used[c[i]]=1; else break; } if (match[a[i]]&&(match[a[i]]<c[i]||match[a[i]]==c[i]&&i==n)) { //for (int j=1;j<=k;j++) tmp[j]=match[j]; bool islim=1;flag=1; for (int j=1;j<=n;j++) { if (match[a[j]]&&match[a[j]]>b[j]) islim=0; if (islim&&match[a[j]]&&match[a[j]]<b[j]) {flag=0;break;} if (!match[a[j]]) { if (!islim) { for (int x=k;x>=1;x--) if (!used[x]) {match[a[j]]=x,used[x]=1;break;} } else { bool f=1; for (int x=k;x>=1;x--) if (!used[x]) { if (x<b[j]) f=0; else match[a[j]]=x,used[x]=1,islim=x==b[j]; break; } if (!f) {flag=0;break;} } } } break; /*if (!flag) { memset(used,0,sizeof(used)); for (int j=1;j<=k;j++) { match[j]=tmp[j]; if (match[j]) used[match[j]]=1; } }*/ }//��ȷ����ijλ������С�ڴ�ĵ����� if (match[a[i]]&&match[a[i]]>c[i]) break; if (flag) break; } if (flag) { printf("YES\n"); for (int i=1;i<=k;i++) if (!match[i]) { for (int x=1;x<=k;x++) if (!used[x]) {match[i]=x,used[x]=1;break;} } for (int i=1;i<=k;i++) putchar(match[i]+'a'-1);printf("\n"); } else printf("NO\n"); } return 0; }View Code
D:考慮什麼樣的人可能成為冠軍。比如這個人出的是石頭,那麼顯然要讓出剪刀的儘量去消滅出布的,為了防止剪刀遇上石頭又要儘量先讓布去消滅其他出石頭的。可以發現事實上不用管其他出石頭的了,考慮一段石頭區間,如果兩端有出布的讓出布的消滅掉即可,否則其兩端都有剪刀,那麼這段石頭對剪刀沒有任何影響。那麼只要其兩端都不是“有出布的但沒有出剪刀的”就好了。現在要統計總共有多少人,對石頭剪刀布各自算一遍,還是考慮石頭,考慮把不合法的石頭去掉,顯然就是第一個布到第一個剪刀之間和最後一個剪刀到最後一個布之間的(有序)。這玩意好像也不難想而且怎麼著也比C好寫幾倍吧?我能不能向天借個30min啊?
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<set> using namespace std; #define ll long long #define int long long #define N 200010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,tree[3][N],a[N]; char s[N]; int val(char c){if (c=='R') return 0;if (c=='P') return 1;if (c=='S') return 2;} void add(int p,int k,int x){while (k<=n) tree[p][k]+=x,k+=k&-k;} int query(int p,int k){int s=0;while (k) s+=tree[p][k],k-=k&-k;return s;} set<int> q[3]; signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); const char LL[]="%I64d\n"; #endif n=read(),m=read(); scanf("%s",s+1); for (int i=1;i<=n;i++) add(a[i]=val(s[i]),i,1),q[val(s[i])].insert(i); for (int j=0;j<=m;j++) { if (j){int x=read(),y=val(getc());add(a[x],x,-1),add(y,x,1);q[a[x]].erase(x),a[x]=y,q[a[x]].insert(x);} int ans=0; for (int i=0;i<3;i++) { int sc=(i+2)%3,pp=(i+1)%3; if (q[pp].empty()) ans+=query(i,n); else if (q[sc].empty()) ; else { ans+=query(i,n); set<int>::iterator it=q[sc].begin();int x=*it; it=q[sc].end();it--;int y=*it; it=q[pp].begin();if ((*it)<x) ans-=query(i,x)-query(i,(*it)); it=q[pp].end();it--;if ((*it)>y) ans-=query(i,(*it))-query(i,y); } } printf("%d\n",ans); } return 0; }View Code
我也不知道為什麼還能漲分。result:rank 208 rating +7