【长沙集训】2017.10.10
?
Adore
1.1 問題描述
小 w 偶然間遇到了一個 DAG。 這個 DAG 有 m 層,第一層只有1個源點,最后一層只有1個匯點,剩下的每一層都有 k 個 節點。
現在小 w 每次可以取反第 i(1 < i < n ? 1) 層和第 i + 1 層之間的連邊。也就是把原本從 (i, k1) 連到 (i + 1, k2) 的邊,變成從
(i, k2) 連到 (i + 1, k1)。 請問他有多少種取反的方案,把從源點到匯點的路徑數變成偶數條? 答案對 998244353 取模。
1.2?輸入格式
第一行兩個整數 m, k。
接下來 m ? 1 行, 第一行和最后一行有 k 個整數 0 或 1,剩下每行有 k 2 個整數 0 或 1,
第 (j ? 1) × k + t 個整數表示 (i, j) 到 (i + 1, t) 有沒有邊。
1.3 輸出格式
一行一個整數表示答案。
1.4 樣例輸入
5 3
1 0 1
0 1 0 1 1 0?0 0 1
0 1 1?1 0 0 0 1 1
0 1 1
1.5樣例輸出
4
1.6數據規模與約定
20% 的數據滿足 n ≤ 10, k ≤ 2
40% 的數據滿足 n ≤ 10^3 , k ≤ 2。
60% 的數據滿足 m ≤ 10^3 , k ≤ 5。
100% 的數據滿足 4 ≤ m ≤ 10^4 , k ≤ 10。
?1.
這要是Noip d1t1我也不用學oi了。。。
每一層只有10個點,我們只關心每個點的奇偶情況,于是可以考慮狀壓dp。dp[i][j]表示第i層奇偶情況為j的答案。
暴力的寫法,枚舉每一層,每種情況,枚舉每條邊暴力地更新奇偶算轉移到的狀態。60分。場上zz不知道哪個地方莫名多了一個忘刪掉的for循環,炸了兩個點。。
優化一下,預處理出連向每個點的邊的集合,用一個二進制串表示,然后每次和轉移來的狀態取交,判斷這個數的1的個數的奇偶(這一步同樣是預處理)。
然后又是垃圾卡常,,可能我真的是傳說中的 真·大常數選手吧。。好不容易卡進去。。
//Twenty #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<vector> #include<cstdio> #include<cmath> #include<ctime> #include<queue> #include<stack> typedef long long LL; const LL mod=998244353; const int maxn=1e4+299; const int maxm=1e6+299; int m,k,x,s,t; using namespace std; int a[maxn][11],b[maxn][11],ok[maxn]; int f[10005][1030];inline int get(int &x) {int ret=0; char ch=getchar();while(ch<'0'||ch>'9') ch=getchar();for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';x=ret; }void work() {int nn=(1<<k)-1;for(register int i=0;i<=nn;i++) ok[i]=ok[i>>1]^(i&1);for(register int i=3;i<=m;i++) {for(register int j=0;j<=nn;j++) if(f[i-1][j]){int now=0,s1=0,s2=0;for(register int l=1;l<=k;l++) {s1|=ok[a[i][l]&j]<<l-1;s2|=ok[b[i][l]&j]<<l-1;}f[i][s1]+=f[i-1][j];if(f[i][s1]>=mod) f[i][s1]-=mod;if(i!=m) {f[i][s2]+=f[i-1][j];if(f[i][s2]>=mod) f[i][s2]-=mod;}}} }int main() {freopen("adore.in","r",stdin);freopen("adore.out","w",stdout);get(m); get(k);int now=0;for(register int i=1;i<=k;i++) {get(x);if(!x) continue;now|=(1<<i-1);}f[2][now]=1;for(register int i=2;i<m-1;i++) {for(register int j=1;j<=k;j++)for(register int l=1;l<=k;l++) {get(x);if(!x) continue;a[i+1][l]|=(1<<j-1);b[i+1][j]|=(1<<l-1);}}for(register int i=1;i<=k;i++) {get(x);if(!x) continue;a[m][1]|=(1<<i-1);}work();printf("%d\n",f[m][0]);fclose(stdin);fclose(stdout);return 0; } View Code?
?
Confess
2.1 問題描述
小w 隱藏的心緒已經難以再隱藏下去了。 小w 有 n + 1(保證 n 為偶數) 個心緒,每個都包含了 [1, 2n] 的一個子集。 現在他要找到隱藏的任意兩個心緒,使得他們的交大于等于 n/ 2。
2.2 輸入格式
一行一個整數 n。
接下來每行一個長度為 k 的字符串,該字符串是一個 64 進制表示,
ASCII 碼為 x 的字符代 表著 x ? 33,所有字符在 33 到 33 + 63 之間。
轉為二進制表示有 6k 位,它的前 2n 個字符就是讀入的集合,
第 i 位為 1 表示這個集合包 含 i,為 0 表示不包含。
2.3 輸出格式
一行兩個不同的整數表示兩個集合的編號。
如果無解輸出”NO Solution”。
2.4 樣例輸入
10
EVK#
IH=#
676"
R7,#
74S"
6V2#
O3J#
S-7$
NU5"
C[$$
3N.#
2.5 樣例輸出
1 2
2.6 數據規模與約定
對于 20% 的數據滿足 n ≤ 100。
對于 50% 的數據滿足 n ≤ 1 × 10^3。
對于 100% 的數據滿足 n ≤ 6 × 10^3。
?2.
t1寫得太難受+語文太爛,沒讀懂題,暴力都沒打直接輸出no solution。
然而沒有No solution的情況,正解就是暴力。
首先”NO Solution” 兩個單詞大小寫不一致,所以肯定是亂 打的,不會有無解。
證明?我們不妨算一算如果隨機選兩個集合,他們交的期望
min( ∑2n i=1 C(ci ,2) C(n+1,2) | ∑2n i=1 ci = n(n + 1)) = n?1/2
注意 n 是偶數,所以大于 n?2/2 即可說明會有交為 n 的
由于大了一個常數,所以至少有 n 對!
隨機 O(n) 對即可
標解用了bitset,開O2跑得賊快,不用bitset就又是垃圾卡常,怎么卡都卡不進,只能一邊輸一遍做找到答案就輸都不輸了才ok。。。
//Twenty #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<vector> #include<cstdio> #include<cmath> #include<ctime> #include<queue> using namespace std; const int maxn=6e3+5; int n,sz,b[maxn]; char ch[60005]; bool a[maxn][2*maxn],tp[10]; int ok(int x,int y) {int ret=0;for(int i=1;i<=2*n;i++) {if(a[x][i]==1&&a[y][i]==1) ret++;if(ret>=n/2) return 1;}return ret>=n/2; } int main() {freopen("confess.in","r",stdin);freopen("confess.out","w",stdout);scanf("%d",&n);for(register int i=1;i<=n+1;i++) {cin>>ch;int p=0,q=0;while(q<=2*n){int mid=ch[p++]-33;for(int j=0;j<6;j++)a[i][++q]=mid&(1<<j);} for(register int j=i-1;j>=1;j--) if(ok(i,j)) {printf("%d %d\n",i,j);return 0;}}fclose(stdin);fclose(stdout);return 0; } View Code--------------------------------------------------------------------------------------------
事實證明被卡常是某個叫random_shuffle()的函數的鍋。換成sort就過了。
還有getchar會比cin快很多。常數這種東西太可怕了。
//Twenty #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<vector> #include<cstdio> #include<cmath> #include<ctime> #include<queue> using namespace std; const int maxn=6e3+5; int n,sz,b[maxn],c[maxn]; char s[105]; bool a[maxn][2*maxn],tp[10]; int ok(int x,int y) {int ret=0;for(int i=1;i<=2*n;i++) {if(a[x][i]==1&&a[y][i]==1) ret++;if(ret>=n/2) return 1;}return ret>=n/2; }bool cmp(const int &x,const int &y) {return b[x]<b[y]; }int main() {freopen("confess.in","r",stdin);freopen("confess.out","w",stdout);srand(time(0));cin>>n;for(int i=1;i<=n+1;i++) {int tot=0; char c=getchar();while(c<33||c>96)c=getchar();while(c>=33&&c<=96) {for(int j=0;j<=5&&tot<=2*n;j++)a[i][++tot]=(((c-33)>>j)&1);c=getchar();}}for(int i=1;i<=n+1;i++) c[i]=i,b[i]=rand();sort(c+1,c+n+2,cmp);for(int i=1;i<=n+1;i++) {for(int j=i+1;j<=n+1;j++)if(ok(c[i],c[i+1])) {printf("%d %d\n",c[i],c[i+1]);return 0;}}fclose(stdin);fclose(stdout);return 0; } View Code?
?
?Repulsed
3.1 問題描述
小 w 心理的火焰就要被熄滅了。 簡便起見,假設小w 的內心是一棵 n ? 1 條邊,n 個節點的樹。 現在你要在每個節點里放一些滅火器,每個節點可以放任意多個。 接下來每個節點都要被分配給一個最多 k 條邊遠的滅火器,每個滅火器最多能分配給 s 個節 點。 最少要多少個滅火器才能讓小 w 徹底死心呢?
3.2 輸入格式
第一行三個整數 n, s, k。
接下來 n ? 1 行每行兩個整數表示一條邊。
3.3 輸出格式
一行一個整數表示答案
3.4 樣例輸入
10 10 3
1 8
2 3
1 5
2 4
1 2
8 9
8 10
5 6
5 7
3.5?樣例輸出
1
3.6 數據規模與約定
對于 20% 的數據滿足 n ≤ 100, k ≤ 2。
對于另外 20% 的數據滿足 k = 1。
對于另外 20% 的數據滿足 s = 1。
對于 100% 的數據滿足 n ≤ 10^5 , k ≤ 20, s ≤ 10
?至底往上貪心。
考慮一條鏈上去只要能管得到肯定往上放比較優,每次從下到上再在上面考慮下面的情況。
g[x][i]表示x點往下i的距離的位置還需要多少滅火器,f[x][i]表示x點往下i的距離的位置有多少沒用的滅火器。
若g[x][k]還不為0,則在該點放滅火器。
考慮子樹中長度為k的距離的位置和k-1距離的位置的互相配放。
到根節點后再把沒用的全用了,還差的一起補上。
//Twenty #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<vector> #include<cstdio> #include<cmath> #include<ctime> #include<queue> const int maxn=1e5+299; int n,s,k; using namespace std;int ans,ecnt,fir[maxn],nxt[maxn*2],to[maxn*2]; void add(int u,int v) {nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; }int f[maxn][22],g[maxn][22]; void dfs(int x,int fa) {for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa){int v=to[i]; dfs(v,x);for(int j=1;j<=k;j++) {f[x][j]=min(n,f[x][j]+f[v][j-1]);g[x][j]+=g[v][j-1];} }g[x][0]++;if(g[x][k]) {int tp=(g[x][k]-1)/s+1;f[x][0]=tp*s,ans+=tp;}for(int i=0;i<=k;i++) {int j=k-i;int d=min(f[x][i],g[x][j]);f[x][i]-=d; g[x][j]-=d;}for(int i=0;i<k;i++) {int j=k-i-1;int d=min(f[x][i],g[x][j]);f[x][i]-=d; g[x][j]-=d;} }int main() {freopen("repulsed.in","r",stdin);freopen("repulsed.out","w",stdout);scanf("%d%d%d",&n,&s,&k);for(int i=1;i<n;i++) {int x,y;scanf("%d%d",&x,&y);add(x,y);}dfs(1,0);for(int i=0;i<=k;i++)for(int j=0;j<=k;j++) {if(i+j<=k) {int d=min(f[1][i],g[1][j]);f[1][i]-=d; g[1][j]-=d;}}int tot=0;for(int i=0;i<=k;i++) {if(g[1][i]) tot+=g[1][i];}ans+=(tot?(tot-1)/s+1:0);printf("%d\n",ans);fclose(stdin);fclose(stdout);return 0; } View Code?
轉載于:https://www.cnblogs.com/Achenchen/p/7647431.html
總結
以上是生活随笔為你收集整理的【长沙集训】2017.10.10的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 神经网络求解NS方程
- 下一篇: 软件技术专业-就业提示(一、实施工程师)